Vous êtes sur la page 1sur 160

Chapitre 5 : Programmation objet et

vnementielle
5.1 Introduction la programmation oriente objet (POO)
concepts fondamentaux de la POO initiation la conception oriente objet (OOD,UML...)

5.2 Programmez objet avec Delphi


Description gnrale de Delphi Modules dans Delphi Delphi et la POO Les proprits en Delphi

5.3 Polymorphisme avec Delphi


Polymorphisme d'objet Polymorphisme de mthodes Polymorphisme de classe abstraite Exercice trait sur le polymorphisme

5.4.Programmation vnementielle et visuelle


programmation visuelle base sur les pictogrammes programmation oriente vnements normalisation du graphe vnementiel tableau des actions vnementielles interfaces lies un graphe vnementiel avantage et modle de dveloppement RAD visuel Notice sur les interfaces de communication

5.5.les vnements avec Delphi


Pointeur de mthode Affecter un pointeur de mthode Un vnement est un pointeur de mthode Quel est le code engendr Exercice-rcapitulatif Notice mthodologique pour crer un nouvel vnement Code pratique : une pile lifo vnementielle

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

445

Exemple trait : Un diteur de texte

5.6.programmation dfensive : les exceptions


Notions de dfense et de protection Outils participant la programmation dfensive Rle et mode daction dune exception Gestion de la protection du code Fonctionnement sans incident Fonctionnement avec incident Effets dus la position du bloc except...end Fonctionnement sans incident Fonctionnement avec incident Interception dune exception dune classe donne Ordre dans linterception dune exception Interception dans lordre de la hirarchie Interception dans lordre inverse Traitement dun exemple de protections Le code de dpart de lunit Code de la version.1 (premier niveau de scurit) Code de la version.2 (deuxime niveau de scurit)

Code pratique : une pile Lifo avec exception

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

446

5.1 Introduction la programmation oriente objet


Plan du chapitre:

Introduction 1. Concepts fondamentaux de La P.O.O


1.1 les objets 1.2 les classes 1.3 Lhritage

2. Introduction la conception oriente objet:


2.1 La mthode de conception OOD 2.2 Notation UML de classes et d'objets SCHEMA UML DE CLASSE VISIBILITE DES ATTRIBUTS ET DES METHODES SCHEMA UML D'UN OBJET SCHEMA UML DE L'HERITAGE SCHEMA UML DES ASSOCIATIONS UNE ASSOCIATION PARTICULIERE : L'AGREGATION NOTATION UML DES MESSAGES 2.3 Attitudes et outils mthodologiques

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

447

Introduction
Le lecteur qui connat les fondements de ce chapitre peut l'ignorer et passer au chapitre suivant. Dans le cas contraire, la programmation visuelle tant intimement lie aux outils et aux concepts objets, ce chapitre est un minimum incontournable. La programmation classique ou procdurale telle que le dbutant peut la connatre travers des langages de programmation comme Pascal, C etc... traite les programmes comme un ensemble de donnes sur lesquelles agissent des procdures. Les procdures sont les lments actifs et importants, les donnes devenant des lments passifs qui traversent larborescence de programmation procdurale en tant que flot dinformation. Cette manire de concevoir les programmes reste proche des machines de Von Neuman et consiste en dernier ressort traiter indpendamment les donnes et les algorithmes (traduits par des procdures) sans tenir compte des relations qui les lient.
En introduisant la notion de modularit dans la programmation structure descendante, lapproche diffre lgrement de lapproche habituelle de la programmation algorithmique classique. Nous avons dfini des machines abstraites qui ont une autonomie relative et qui possdent leurs propres structures de donnes; la conception dun programme relevait ds lors essentiellement de la description des interactions que ces machines ont entre elles.

La programmation oriente objet relve d'une conception ascendante dfinie comme des "messages" changs par des entit de base appeles objets. comparaison des deux topologies de programmation

Les langages objets sont fonds sur la connaissance dune seule catgorie dentit informatique : lobjet. Dans un objet, traditionnellement ce sont les donnes qui deviennent
Les bases de linformatique - programmation - ( rv. 04.01.2005 ) page

448

prpondrantes. On se pose dabord la question : "de quoi parle-t-on ?" et non pas la question "que veut-on faire ?", comme en programmation algorithmique. Cest en ce sens que les machines abstraites de la programmation structure modulaire peuvent tre considres comme des pr-objets. En fait la notion de TAD est utilise dans cet ouvrage comme spcification dun objet, en ce sens nous nous proccupons essentiellement des services offerts par un objet indpendamment de sa structure interne.

Programmation structure :

1. Concepts fondamentaux de La P.O.O


Nous crirons P.O.O pour : programmation oriente objet.

Voici trois concepts qui contribuent la puissance de la P.O.O. Concept de modlisation travers la notion de classe et dinstanciation de ces classes. Concept daction travers la notion denvoi de messages et de mthodes lintrieur des objets. Concept de construction par rutilisation et amlioration par lutilisation de la notion dhritage.

1.1 les objets Objet Un module reprsente un objet ou une classe dobjet de lespace du problme et non une tape principale du processus total, comme en programmation descendante.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

449

Recenser les objets du monde rel Lors de lanalyse du problme, on doit faire ltat de lexistant en recensant les objets du monde rel. On tablit des classes dobjets et pour chaque objet on inventorie les connaissances que lon a sur lui : Les connaissances dclaratives, les connaissances fonctionnelles, lobjet rel et les connaissances que lon a sur lui sont regroups dans une mme entit.

On dcrit alors les systmes en classes dobjets plutt quen terme de fonctions.

Par Exemple : Une application de gestion bancaire est organise sur les objets comptes, critures, tats. Les objets rassemblent une partie de la connaissance totale portant sur le problme. Cette connaissance est rpartie sur tous les objets sous forme dclarative ou procdurale. Les objets sont dcrits selon le modle des structures abstraites de donnes (TAD) : ils constituent des botes noires dissimulant leur implantation avec une interface publique pour les autres objets. Les interactions stablissant travers cette interface.

Vocabulaire objet
Encapsulation
cest le fait de runir l'intrieur d'une mme entit (objet) le code (mthodes) + donnes (champs). Il est donc possible de masquer les informations d'un objet aux autres objets. Deux niveaux dencapsulation sont dfinis :

Priv
les champs et les mthodes masqus sont dans la partie prive de lobjet.

Public
les champs et les mthodes visibles sont dans la partie interface de lobjet.

Les notions de priv et de public comme dans un objet n'ont trait qu' la communication entre deux objets, l'intrieur d'un objet elles n'ont pas cours.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

450

Figure sur la visibilit entre deux objets Les mthodes de public ou priv de l'objet A accdent et peuvent utiliser les mthodes et les champs public de B. Les mthodes de public ou priv de l'objet B accdent et peuvent utiliser les mthodes et les champs public de A.

1.2 les classes Postulons une analogie entre les objets matriels de la vie courante et les objets informatiques. Un objet de tous les jours est souvent obtenu partir dun moule industriel servant de modle pour en fabriquer des milliers. Il en est de mme pour les objets informatiques. Classe Une classe est une sorte de moule ou de matrice partir duquel sont engendrs les objets rels qui sappellent des instances de la classe considre. Une classe contient Des attributs (ou champs, ou variables dinstances).
Les attributs de la classe dcrivent la structure de ses instances (les objets).

Des mthodes (ou oprations de la classe).


Les mthodes dcrivent les oprations qui sont applicables aux instances de la classe.

Membres les attributs et les mthodes d'une classe sont des membres de la classe.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

451

Instance Un objet de classe A est appel aussi une instance de classe A, l'opration de construction d'un objet s'appelle alors l'instanciation.

Remarque En POO, programmer revient donc dcrire des classes dobjets, caractriser leur structure et leur comportement, puis instancier ces classes pour crer des objets rels. Un objet rel est matrialis dans lordinateur par une zone de mmoire que les donnes et son code occupent.

Un exemple : des tudiants Supposons que chaque tudiant soit caractris par sa note en mathmatiques (NoteMath) et sa note en informatique (NoteInfo). Un tudiant doit pouvoir effectuer ventuellement des oprations de calcul de ses moyennes dans ces deux matires (MoyMath, MoyInfo)et connatre sa moyenne gnrale calcule partir de ces deux notes (MoyTotale).

La classe Etudiant a t cre. Elle ne possde que les attributs NoteMath et NoteInfo. Les mthodes de cette classe sont par exemple MoyMath, MoyInfo, MoyTotale. Nous avons cr deux objets tudiants de la classe Etudiant (deux instances : Julien et Claudie).

1.3 Lhritage Dans un LOO (Langage Orient Objet), il existe une particularit dans la faon dorganiser ses classes : lhritage de proprits. Lobjectif est de construire de nouvelles classes en rutilisant des attributs et des mthodes de classes dj existantes. Hritage Cest un mcanisme trs puissant qui permet de dcrire des structures gnriques en transmettant depuis lintrieur dune mme classe toutes les proprits communes toutes les " sous-classes " de cette classe. Par construction toutes les sous-classes dune mme classe possdent toutes les attributs et les mthodes de leur classe parent.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

452

Proprits de l'hritage Les attributs et les mthodes peuvent tre modifis au niveau de la sous-classe qui hrite. Il peut y avoir des attributs et/ou des mthodes supplmentaires dans une sous-classe. Une classe A qui hrite dune classe B dispose implicitement de tous les attributs et de toutes les mthodes dfinis dans la classe B. Les attributs et les mthodes dfinis dans A sont prioritaires par rapport aux attributs et aux mthodes de mme nom dfinis dans

Exemple : La classe " Etudiant premier cycle" hritant de la classe Etudiant prcdemment dfinie.

Tout se passe comme si toute la classe Etudiant tait recopie dans la sous-classe Etudiant premier cycle (mme si limplmentation nest pas faite ainsi).

La nouvelle classe dispose dun attribut supplmentaire (Mention) et dune mthode supplmentaire (EvaluerMention).

type Tmention=(Passable, Abien, Bien, Tbien); Etudiant = class NoteMath : real; NoteInfo : real; procedure MoyMath(UneNote:real); procedure MoyInfo(UneNote:real); function MoyTotale : real ; end; Etudiant1erCycle = class(Etudiant) Mention: Tmention ; function EvaluerMention: Tmention; end;

Ceci est une implantation possible de la signature de la classe en :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

453

class Etudiant { public float NoteMath; public float NoteInfo; public void MoyMath(float UneNote){ Ceci est une implantation ... } public void MoyInfo(float UneNote){ possible de la signature de la ... } classe en : public float MoyTotale(){ ... } }// fin classe Etudiant public class Etudiant1erCycle extends Etudiant{ public String Mention; public String EvaluerMention( ){ ... } public static void Main(String[ ] args){ ... } }// fin

Exemples dhritage dans dautres domaines :


Hritage dans les structures mathmatiques :

Hritage de figures de base en gomtrie affine :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

454

Hritage d'objets graphiques dans un systme multi-fentr fictif :

2. Introduction la conception oriente objet


Lattitude est ici rsolument sous-tendue par un double souci : fournir des outils mthodologiques rationalisant leffort de production du logiciel, sans que leur lourdeur rebute ltudiant non professionnel et masque ainsi lintrt de leur utilisation. Lexprience denseignement de lauteur avec des dbutants a montr que si les tudiants sont appels dvelopper sans outils mthodiques, ils pratiquent ce quappelle J.Arsac " la grande bidouille ". Mais dans le cas contraire, lapprentissage dtaill de trop de mthodes strictes bien qu'efficaces (OOD, OMT, HOOD, UML,...)finit par ennuyer ltudiant ou du moins par endormir son sens de lintrt. Dans ce dernier cas lon retrouve " la grande bidouille " comme tape finale. Le chemin est donc troit et il appartient chaque enseignant de doser en fonction de lauditoire lutile et le superflu. Nous utilisons ici un de ces dosages pour montrer ltudiant comment crire des programmes avec des objets sans tre un grand spcialiste. Une aide irremplaable cet gard nous sera fournie par lenvironnement de dveloppement visuel Delphi.

2.1 La mthode de conception OOD simplifie La mthode O.O.D (object oriented design) de G.Booch propose 5 tapes dans ltablissement dune conception oriente objet. Ces tapes nont pas obligatoirement tre enchanes dans lordre dans lequel nous les citons dans le paragraphe suivant. Cest cette souplesse qui nous a fait choisir la dmarche de G.Booch, car cette mthode est fondamentalement incrmentale et nimpose pas un cadre trop prcis et trop rigide dans son application. Cette dmarche se rvle tre utile pour un dbutant et lui permettra de fabriquer en particulier des prototypes avec efficacit sans trop surcharger sa mmoire.
Les bases de linformatique - programmation - ( rv. 04.01.2005 ) page

455

Identifier les objets et leurs attributs On cherchera identifier les objets du monde rel que lon voudra raliser. Conseil : Il faut identifier les proprits caractristiques de lobjet (par lexprience, lintuition,...).On pourra saider dune description textuelle (en langage naturel) du problme. La lecture de cette prose aidera dduire les bons candidats pour les noms utiliser dans cette description ainsi que les proprits des adjectifs et des autres qualifiants. Identifier les opration On cherchera ensuite identifier les actions que lobjet subit de la part de son environnement et quil provoque sur son environnement. Conseil : Les verbes utiliss dans la description informelle (textuelle) fournissent de bons indices pour lidentification des oprations. Si ncessaire, cest cette tape que lon pourra dfinir les conditions dordonnancement temporel des oprations (les vnements ayant lieu). Etablir la visibilit Lobjet tant maintenant identifi par ses caractristiques et ses oprations, on dfinira ses relations avec les autres objets. Conseil : On tablira quels objets le voient et quels objets sont vus par lui (les spcialistes disent alors quon insre lobjet dans la topologie du projet). Il faudra prendre bien soin de dfinir ce qui est visible ou non, quitte y revenir plus tard si un choix sest rvl ne pas tre judicieux. Etablir linterface Ds que la visibilit est acquise, on dfinit linterface prcise de lobjet avec le monde extrieur. Conseil : Cette interface dfinit exactement quelles fonctionnalits sont accessibles et sous quelles formes. Cette tape doit pouvoir tre dcrite sous notation formelle; les TAD sont loutil que nous utiliserons cette tape de conception. Implmenter les objets La dernire tape consiste implanter les objets en crivant le code. Conseil : Cette tape peut donner lieu la cration de nouvelles classes correspondant par exemple des ncessits dimplantation. Le code en gnral correspond aux spcifications concrtes effectues avec les TAD, ou la traduction des algorithmes dvelopps par la mthode structure. Lors de cette tape, on identifiera ventuellement de nouveaux objets de plus bas niveau dabstraction qui ne pouvaient pas tre analyss en premire lecture(ceci provoquant litration de la mthode ces niveaux plus bas). Nous nopposons pas cette mthode de conception la mthode structure modulaire. Nous la considrons plutt comme complmentaire (en appliquant des dbutants une ide contenue dans la mthode HOOD). La mthode structure modulaire sert laborer des algorithmes classiques comme des actions sur des donnes. La COO permet de dfinir le monde de lenvironnement de faon modulaire. Nous rutiliserons les algorithmes construits dans des objets afin de montrer la complmentarit des deux visions.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

456

2.2 Notation UML de classes et d'objets La notion d'un langage de modlisation standard pour tout ce qui concerne les dveloppements objets a vu le jour en 1997 il sagit dUML (Unified Modeling Language). UML n'est pas une mthode, mais une notation graphique et un mtamodle. Nous allons fournir ici les principaux schmas d'UML permettant de dcrire des dmarches de conception objets simples. Le document de spcification de la version 1.4 d'UML par l'OMG (l'Object Management Group) reprsente 1400 pages de dfinitions smantiques et de notations; il n'est donc pas question ici de dvelopper l'ensemble de la notation UML (que d'ailleurs l'auteur ne possde pas lui-mme). Nous nous attacherons dtailler les diagrammes de base qui pourront tre utiliss par la suite dans le reste du document. Nous nous limiterons aux notations relatives aux classes, aux objets, et l'hritage.

SCHEMA UML DE CLASSE


Notations UML possibles d'une classe : Reprenons l'exemple prcdent avec la classe tudiant :

trois notations UML possibles

Simplifie

Avec attributs

Attributs et mthodes

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

457

Deux autres notations UML plus complte pour la mme classe

Attributs et mthodes types

Attributs typs et mthodes types

Une classe abstraite est note :

VISIBILITE DES ATTRIBUTS ET DES METHODES


Notation prfixe UML pour trois niveaux de visibilit ( +, - , # , $) : Pour les attributs : priv - Attribut2 : DeType2 Pour les mthodes : priv - Methode2 ( ) : DeType2 Mthode de classe $ Methode4 ( ) : DeType4 Explicitation dans la classe Etudiant : Dans la classe tudiant les deux attributs NoteMath et NoteInfo sont de type rel et sont privs (prfixe -). Les trois mthodes de calcul de moyennes sont publiques (prfixe +).

public + Attribut1 : DeType1

protg # Attribut3 : DeType3

public + Methode1 ( ): DeType1

protg # Methode3 ( ) : DeType3

SCHEMA UML D'UN OBJET


Notations UML pour deux objets tudiants instancis partir de la classe Etudiant : Schma UML simplifi :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

458

Schma UML avec valeur des attributs :

Ces notations correspondent l'exemple ci-dessous :

SCHEMA UML DE L'HERITAGE


Notation UML de l'hritage :

Soit pour l'exemple de hirarchie de classes fictives ci-dessous :

La notation UML suivante :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

459

SCHEMA UML DES ASSOCIATIONS


Une association binaire (ou plus gnralement n-aire), reprsente un lien conceptuel entre deux classes. Par exemple un tudiant travaille dans un groupe (association entre la classe Etudiant et la classe Groupe).

Une association peut tre dnote par une expression appele nom d'association (nomm Travailler ci-dessous) :

Chaque association possde donc deux extrmits appeles aussi rles, il est possible de nommer les extrmits (nom de rles, ci-dessous un tudiant est un acteur travaillant dans un groupe qui est un ensemble) :

Une association peut possder une multiplicit qui reprsente sous forme d'un intervalle de nombres entiers a..b, le nombre d'objets de la classe d'arrive qui peut tre mis en association avec un objet de la classe de dpart. Supposons qu'un tudiant doive s'inscrire au moins 2 groupes de travail et au plus 5 groupes, nous aurons le schma UML suivant :

La prsence d'une toile dans la multiplicit indiquant un nombre quelquonque (par exemple un tudiant peut s'inscrire au moins 2 groupes sans limite suprieure):

Par exemple pour dnoter en UML le fait qu'un nombre quelconque d'tudiants doit travailler dans au moins deux groupes nous crirons:

UNE ASSOCIATION PARTICULIERE : L'AGREGATION


Une agrgation est une association correspondant une relation qui lorsqu'elle est lue dans un sens signifie "est une partie de" et lorsqu'elle est lue dans l'autre sens elle signifie "est compos de". UML disposant de plusieurs raffinements possibles nous utiliserons l'agrgation comme composition par valeur en ce sens que la construction du tout implique la construction automatique de toutes les parties et que la destruction du tout entrane en cascade la destruction de chacune de ses parties.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

460

Notation UML de l'agrgation

Exemple :
un groupe contient au moins 3 tudiants et chaque tudiant doit s'inscrire au moins 2 groupes :

NOTATION UML DES MESSAGES


Un message envoy par une classe une autre classe est reprsent par une flche vers la classe qui s'adresse le message, le nommage de la flche indique le message excuter :

2.3 Attitudes et outils mthodologiques Afin dutiliser une mthodologie pratique et rationnelle, nous numrons au lecteur les outils que nous utilisons selon les besoins, dans le processus dcriture dun logiciel.
En tout premier la notion de module : Cest la dcomposition dun logiciel en sous-ensembles que lon peut changer comme des pices dun patchwork. La notion de cycle de vie du logiciel : Dvelopper un logiciel ce nest pas seulement crire du Pascal, de lAda etc... Utiliser des TAD : Un type abstrait de donnes correspond trs exactement linterface dun module. Il renforce la mthodologie modulaire. La programmation structure par machines abstraites : On se sert dune mthode de conception descendante et modulaire des algorithmes utiles pour certaines actions dans le logiciel. La conception et la programmation orientes objet : On utilise une version simplifie de la COO de G.Booch pour dfinir les classes et leurs relations en attendant une simplification pdagogique dUML.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

461

5.2 Programmez objet avec Delphi


Plan du chapitre: 1. Description gnrale de Delphi
1.1 L'application Delphi 1.2 Les fiches et les contrles

2. Les modules dans Delphi


2.1 Partie " public " dune UNIT : " Interface " 2.2 Partie " prive " dune UNIT : " Implementation " 2.3 Initialisation et finalisation dune UNIT

3. Delphi et la POO
3.1 Les lments de base 3.2 Fonctionnalits 3.3 Les classes 3.3.1 Mta-classe 3.3.2 Classe amie 3.4 Le modle objet 3.5 Les objets 3.6 Encapsulation 3.7 Hritage 3.8 Polymorphisme - surcharge (bases) 3.9 En rsum 3.10 Activit vnementielle

4. Les proprits en Delphi


4.1 Dfinition 4.2 Accs par read/write aux donnes d'une proprit 4.3 Proprits tableaux 4.4 Surcharge de proprit

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

462

Introduction
Delphi de Borland est un RAD visuel fond sur une extension oriente objet, visuelle et vnementielle de Pascal, il fonctionne depuis 2004 sous le systme Windows toutes versions, sous Linux et sous l'architecture .Net. Pascal est le langage utilis pour linitiation dans de trs nombreux tablissements denseignement europens. Le RAD Delphi est un prolongement intressant de ce langage. Nous allons explorer certains aspects les plus importants et significatifs du pascal objet de Delphi. Le langage pascal de base tant suppos connu par le lecteur, nous souhaitons utiliser ce RAD visuel en rutilisant du savoir faire pascal tout en y rajoutant les possibilits objet offertes par Delphi.

1. Description minimale de Delphi ...


La version utilise pour crire les exemples est la dernire disponible sur Windows, mais tous les exemples sont crits avec les fonctionnalits gnrales de Delphi ce qui permet de les compiler sur n'importe quelle version de Delphi depuis la version 5.

1.1 L'application Delphi Une application console (non fentre) Delphi se compose d'un projet "xxx.dpr" et d'au minimum un fichier d'Unit "xxx.pas" pour le code source. Lors de la compilation d'un projet Delphi engendre un code "xxx.exe" directement excutable.

Tous les projets Delphi s'excutent sous windows sans aucune Dll supplmentaire autre que celles que vous programmerez vous-mme :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

463

Une application fentre Delphi se compose d'un projet "xxx.dpr" et d'au minimum deux fichiers de fiche "xxx.dfm" pour la description et "xxx.pas" et d'Unit pour le code source.

Ci-contre un projet minimal Delphi comportant une fiche principale. Le projet se dnomme Project1.dpr La fiche principale Form1 et le code source de l'application sont rangs dans la Unit Unit1.pas. La description de la fiche Form1 et de ce qu'elle contient se trouve dans un fichier nomm Unit1.dfm.

A quoi sert une fiche ?


Les systmes d'exploitation actuels sont dit fentrs au sens o ils fournissent un mode de communication avec l'homme fond sur la notion de fentre, Windows en est un exemple. La premire action entreprendre lors du dveloppement d'une application Interface Homme Machine (IHM) avec un langage de programmation, est la cration de l'interface de l'application et ensuite les interactions avec l'utilisateur. Le langage de programmation doit donc permettre de construire au moins une fentre
La fiche Form1 du projet Projet1 minimal

En Delphi pour crer une IHM, il faut utiliser des fiches (ou fentres) et des contrles. Ces fiches sont des objets au sens informatique de la POO, mais elles possdent une reprsentation visuelle.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

464

1.2 Les objets de fiches et les objets contrles Chaque fiche est en fait un objet instanci partir de la classe interne des TForm de Delphi. Cette classe possde des proprits(attributs) qui dcrivent l'apparence de la fiche, des mthodes qui dcrivent le comportement de la fiche et enfin des gestionnaires d'vnements (pointeurs de mthodes) qui permettent de programmer la raction de la fiche aux vnements auxquels elles est sensible. Sur une fiche vous dposez des contrles qui sont eux aussi d'autres classes d'objets visuels, mais qui sont contenus dans la fiche. Ci-dessous la palette des composants de Delphi dposables sur une fiche :

la fiche Form1 tat initial

la fiche Form1 aprs dpt de 3 contrles

Que se passe-t-il lors du dpt des contrles ?


code dans la fiche Form1 avant dpt code dans la fiche Form1 aprs dpt
unit Unit1; unit Unit1; interface interface uses uses Windows, Messages, SysUtils, Classes, Graphics, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; Controls, Forms, Dialogs; type type TForm1 = class(TForm) TForm1 = class(TForm) private Memo1: TMemo; { Dclarations prives } Button1: TButton; public Edit1: TEdit; { Dclarations publiques } private end; { Dclarations prives } public var Form1: TForm1; { Dclarations publiques } end; implementation {$R *.DFM} var end. Form1: TForm1; implementation {$R *.DFM} end.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

465

Il existe dans Delphi une notion de classe conteneur, la fiche (classe TForm) en est le principal reprsentant. Delphi est un gnrateur automatique de programme source Pascal objet et ds l'ouverture du projet, il dfinit une classe conteneur TForm1 qui hrite de la classe TForm et qui au dpart ne contient rien :
TForm1 = class(TForm) private { Dclarations prives } public { Dclarations publiques } end;

Lorsque nous dposons les 3 contrles Button1, Edit1, Memo1, ce sont des champs objets qui sont automatiquement ajouts par Delphi dans le code source de la classe :
TForm1 = class(TForm) Memo1: T Memo; Button1: TButton; Edit1: TEdit; private { Dclarations prives } public { Dclarations publiques } end;

Donc l'environnement Delphi, n'est pas seulement un langage de programmation, mais aussi un gnrateur de programme partir de dpt de composants visuels, c'est la fonction d'un systme RAD (Rapid Application Developpement). Pour une utilisation de Delphi, nous renvoyons le lecteur la documentation du constructeur, nous attachons par la suite faire ressortir et utiliser les lments de Delphi qui concernent la programmation modulaire et la programmation objet

2. Les modules dans Delphi


Nous avons dj vu au chapitre sur les TAD (types abstraits de donnes) que le Pascal de Delphi permettait de traduire sous une premire forme la notion de type abstrait : la Unit. Une Unit Delphi permet aussi de reprsenter la notion de module.

Une Unit est une unit compilable sparment de tout programme et stockable en bibliothque. Une Unit comporte une partie " public " et une partie " priv ". Elle implante donc lide de module et tend la notion de bloc (procdure ou fonction) en Pascal. Elle peut contenir des descriptions de code simple ou de classe.

Chaque unit Unit est stocke dans un fichier xxx.pas distinct et compile sparment ; les units compiles (les fichiers xxx.DCU) sont lies pour crer une application.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

466

Les units en Delphi permettent aussi : De diviser de grands programmes en modules qui peuvent tre modifis sparment. De crer des bibliothques qui peuvent tre partages par plusieurs programmes. De distribuer des bibliothques d'autres dveloppeurs sans leur donner le code source.

Pour gnrer un code xcutable partir d'un projet comportant plusieurs units, le compilateur Delphi doit disposer, pour chaque unit, soit du fichier source xxx.PAS, soit du fichier XXX.DCU rsultant d'une compilation antrieure. Cette dernire possibilit permet de fournir des units compiles d'autres personnes sans leur fournir le code source. Syntaxe d'une unit : Unit Truc; <partie public > <partie prive > <initialisation > end. Utilisation d'une unit : Le programme principal se nomme le projet, il est rang dans le fichier "xxx.dpr". Ici le programme principal utilise 3 Unit : UnitA , UnitB et UnitC

Squelette du code associ au schma prcdent :


unit UnitA; interface implementation end. unit UnitB; interface implementation end. unit UnitC; interface implementation end. Program project1; Uses UnitA, UnitB, UnitC; Begin end.

Fichiers disque (sources et compils) associs au code prcdent :


project1.dpr UnitA.pas UnitA.pas UnitA.pas

Aprs compilation

project1.exe UnitA.dcu UnitA.dcu UnitA.dcu

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

467

Pour ajouter au projet une nouvelle Unit : On peut utiliser l'environnement d'ajout de Delphi : On peut crire soi-mme un fichier texte contenant la unit :
unit Unit2; interface implementation end.

Et rajouter soi-mme au texte source du programme principal la unit :


Program project1; Uses Unit2 ; Begin end.

qui cre par exemple un fichier Unit2.pas contenant le squelette de la Unit2 et rajoute automatiquement cette unit au programme principal.

2.1 Partie " public " dune UNIT : " Interface " Cette partie d'une unit, correspond exactement la partie publique du module reprsent par la UNIT. Cette partie dcrit les en-ttes des procdures et des fonctions publiques et utilisables par les clients. Les clients peuvent tre soit dautres procdures Delphi, des programmes Delphi ou dautres Unit. La clause Uses XXX dans un programme Delphi, permet dindiquer la rfrence la Unit XXX et autorise laccs aux procdures et fonctions publiques de linterface dans tout le programme. Syntaxe de l'interface :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

468

2.2 Partie " prive " dune UNIT : " Implementation " Correspond la partie prive du module reprsent par la UNIT. Cette partie intimement lie linterface, contient le code interne du module. Elle contient deux sortes dlments : les dclarations compltes des procdures et des fonctions prives ainsi que les structures de donnes prives. Elle contient aussi les dclarations compltes des fonctions et procdures publiques dont les en-ttes sont prsentes dans linterface. Syntaxe de l'implementation :

2.3 Initialisation et finalisation dune UNIT Syntaxe de l'initialisation :


La partie initialisation d'une unit en Delphi comporte deux sous parties Initialization et Finalization la seconde tant optionnelle:

Initialization
Il est possible d'initialiser des variables et d'excuter des instructions au lancement de l'UNIT. Elles correspondent des instructions classiques Pascal sur des donnes publiques ou prives de la Unit (initialisation de tableaux, mise zro de divers indicateurs, chargement de fichiers etc...).

Finalization
Une fois que le code d'initialisation d'une unit a commenc s'excuter, la section de finalisation correspondante si elle existe, s'excute obligatoirement l'arrt de l'application (libration de mmoire, de fichiers, rcupration d'incidents etc...).

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

469

Exemple de programme console modulaire


Unit Delphi Uratio du TAD rationnel
unit Uratio; {unit de rationnels spcification classique ZxZ/R} interface type rationnel = record num: integer; denom: integer end; procedure reduire (var r: rationnel); procedure addratio (a, b: rationnel; var s: rationnel); procedure divratio (a, b: rationnel; var s: rationnel); procedure mulratio (a, b: rationnel; var s: rationnel); procedure affectQ(var s: rationnel; b: rationnel); procedure opposeQ(x:rationnel;var s:rationnel); implementation procedure reduire . procedure addratio . Procedure divratio . procedure mulratio . procedure affectQ. procedure opposeQ. end.

Programme principal Delphi utilisant Uratio


program essaiRatio; {programme de test de la unit Uratio } {$APPTYPE CONSOLE} uses SysUtils , Uratio; var r1, r2, r3, r4, r5: rationnel; begin r1.num :=18; r1.denom := 15; r2.num := 7; r2.denom := 12; addratio(r1, r2, r3); writeln('18/15 + 7/12 = ', r3.num, '/', r3.denom); mulratio(r1, r2, r4); writeln('18/15 * 7/12 = ', r4.num, '/', r4.denom); divratio(r1, r2, r5); writeln('18/15 / 7/12 = ', r5.num, '/', r5.denom); r1.num := 72; r1.denom := 60; affectQ(r3,r1); reduire(r1); writeln('72/60 = ', r1.num, '/', r1.denom); writeln('avant rduction ', r3.num, '/', r3.denom); end.

Exemple fiche : le programme lanant une fiche vierge


unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) private { Dclarations prives } public { Dclarations publiques } end; var Form1: TForm1; implementation {$R *.DFM} end. program Project1; uses Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

470

3. Delphi et la POO ...


Notre objectif est d'apprendre comment Delphi implante les notions contenues dans la P.O.O. et d'utiliser ces outils dans nos programmes. Delphi est un langage orient objet, dans ce domaine il possde des fonctionnalits quivalentes C++ et java, avec sa version .Net, il possde les fonctionnalits quivalentes celles de C# de microsoft. 3.1 Les lments de base Sachons que dans Delphi tout est objet, des contrles de la VCL (Visual Component Library commportant plus de 600 classes dont environ 75 sont visuelles, les autres tant non visuelles ou concernant des objets de service). Delphi possde de par son fondement sur Object Pascal tous les types prdfinis du pascal et les constructeurs de types (supposs connus du lecteur), plus des types prdfinis tendus spcifique Delphi. Ce qui signifie qu'il est tout fait possible de rutiliser en Delphi sans effort de conversion ni d'adaptation tout programme pascal ISO ou UCSD dj crit. Les types integer, real et string sont des types gnriques c'est dire qu'ils s'adaptent tous les types d'entiers, de rels et de chanes de Delphi. Par exemple les entiers de base de Delphi suivants : Shortint -128..127 8 bits sign Smallint -32768..32767 16 bits sign Longint -2147483648..2147483647 32 bits sign Byte 0..255 8 bits non sign Word 0..65535 16 bits non sign Longword 0..4294967295 32 bits non sign peuvent tre affects une variable x : integer car c'est un type gnrique.
var x : integer ; a : Longint; b : Longword; c: Byte; d: Word; e: Smallint; f: Shortint; x := a ; x := b ; x := c ; x := d ; x := e ; x := f ;

Delphi dispose d'un type gnrique variant polymorphe sur les types de donnes prdfinis de Delphi. Un variant peut s'adapter ou se changer en pratiquement n'importe quel type de Delphi

Var x : variant; begin x:='abcdefgh'; // x est une string x:=123.45; // x est un real x:=true; // x est un boolen x:=5876 // x est un integer

etc...

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

471

Les passages des paramtres s'effectuent principalement selon les deux modes classiques du pascal : le passage par valeur (pas de mot cl), le passage par rfrence (mot cl Var). Par dfaut si rien n'est spcifi le passage est par valeur. Amliorations de ces passages de paramtres : Delphi autorise un mode de passage dit des paramtres constants permettant une scurit accrue au passage par valeur (mot cl Const).

Delphi dispose d'une autre amlioration concernant le passage par rfrence : le passage par sortie (mot cl out), qui indique simplement la procdure o placer la valeur en sortie sans spcifier de valeur en entre, qui si elle existe n'est pas utilise.

Exemple d'utilisation des variant dans un tri rcursif sur un tableau de variant : (les paramtres sont tous passs par La procdure gnrique quicksort permet de trier un tableau rfrence )
const n=100; type Tableau =array[0..n] of variant; procedure quicksort (var G,D:integer; var tabl:Tableau); var i , j : Integer; x , w : variant; begin i := G; j := D; x := tabl[(i + j) div 2]; repeat While tabl[i] < x do i := i + 1; While tabl[j] x do j := j - 1; If i <= j Then begin w := tabl[i]; tabl[i] := tabl[j]; tabl[j] := w; i := i + 1; j := j - 1 End; Until i j; If G < j Then quicksort(G, j, tabl); If D i Then quicksort(i, D, tabl) End; de variant. Grce son pouvoir polymorphe un variant peut devenir au choix soit: Entier long Entier court Un rel simple ou double Une chane de caractres. Ce qui revient dire que la procdure gnrique quicksort permet de trier un tableau de : Entiers longs Entiers courts Rels simples ou doubles Chanes de caractres. Dans le cas o le type variant n'existe pas, il faut au moins 3 procdures diffrentes quicksortXXX qui diffrent par le type de leur paramtres, mais avec le mme code : procedure quicksortEntier (sur un tableau d'integer) procedure quicksortReel (sur un tableau de real) procedure quicksortString (sur un tableau de string)

Remarque : D'autres modes de passage des paramtres sont possibles en Delphi, nous n'en parlons pas ici.

3.2 Fonctionnalits du pascal objet de Delphi Delphi est un langage structure de blocs complet. Sa gestion est identique celle du langage pascal.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

472

La visibilit est identique celle qui est inhrente tout langage de bloc Algol-like : variables globales, variables locales, masquage des identificateurs. Les entits gres dynamiquement le sont selon un modle classique de tas et de pile d'excution. Les entits gres d'une faon permanente (donnes globales)sont persistantes durant toute la dure de l'excution du programme, elles existent dans le segment de donnes allou l'application.

Dans un langage structure de bloc comme Delphi, la mmoire centrale contient deux entits fondamentales : le tas et de pile d'excution.

Le tas est une structure de donnes dj tudie (arbre parfait partiellement ordonn gr dans un tableau). La pile d'excution est une pile LIFO.

La pile d'excution de Delphi a une taille paramtrable par le programmeur (maximum=2 147 483 647 octets), elle permet toutes les rcursivits utiles. Ci-dessous l'illustration du fonctionnement du tas et de la pile dans le cas de l'appel d'une procdure P0 qui appelle une procdure P1 qui appelle elle-mme une procdure P2:

Le tas contient les structures dynamiques et les codes. La pile d'excution contient les contextes des procdures appeles.

procedure P0; begin P1 end: procedure P1; begin P2 end:

Delphi est un langage acceptant la rcursisvit


La rcursivit d'une procdure ou d'une fonction est la capacit que cette fonction/procdure a de s'appeler elle-mme. Soit par exemple la somme des n premiers entiers dfinie par la suite rcurrente Sn : Sn = Sn-1 + n S0 = 0
Les bases de linformatique - programmation - ( rv. 04.01.2005 ) page

473

Ci-dessous une fonction de calcul rcursif de la somme des n premiers entiers : Function S(n : integer) : integer; begin If n = 0 Then result:= 0 Else result := n + S(n - 1) End;
Delphi affiche un message d'erreur de pile pleine sur l'appel S(129937), donc une profondeur de 129936 appels recursifs a t atteinte sur ce programme avec le paramtrage standard fournit de 1 Mo comme taille maximum de la pile.

3.3 Les classes La notion de classe est essentielle dans Delphi en mode application visuelle. Les classes sont dclares comme des types et contiennent des champs, des mthodes et des proprits. Il existe une classe d'objet primitive appele TObject , qui est l'anctre de toutes les autres classes de Delphi.
Voici un extrait de la hirarchie des classes visuelles VCL (Visual Component Library) dans Delphi :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

474

Comment dclarer une classe en Delphi


Un type classe doit tre dclar et nomm avant de pouvoir tre instanci. Une classe est considr par Delphi comme un nouveau type et doit donc tre dclar l o en Pascal l'on construit les nouveaux types : au paragraphe des dclarations l'alina de dclaration des types. Les types classes peuvent tre dclars pratiquement partout o le mot cl type est autoris l'exception suivante : ils ne doivent pas tre dclars l'intrieur d'une procdure ou d'une fonction.
Les deux dclarations ci-dessous sont quivalentes :

Type ma_classe = class {dclarations de champs } {spcification mthodes } {spcification proprits } end;

Type ma_classe = class(Tobject) {dclarations de champs } {spcification mthodes } {spcification proprits } end;

Mta-classe
Delphi autorise la construction de mta-classes. Une Mta-classe est un gnrateur de classe. En Delphi les mta-classes sont utilises afin de pouvoir passer des paramtres dont la valeur est une classe dans des procdures ou des fonction. Les mta-classes en Delphi sont reprsentes par une rfrence de classe

Une mta-classe
Type TMetaWinClasse = class of TWinControl;

Une variable de mta-classe


var x : TMetaWinClasse;

La variable x de classe TMetaWinClasse, peut contenir une rfrence sur n'importe quelle classe de TWinControl : x :=Tmemo; x :=TEdit; x :=TButton;
Exemple d'utilisation de la notion de mtaclasse pour tester le type rel du paramtre effectif lors de l'appel de TwinEssai. procedure TwinEssai (UnWinControl : TmetaWinClasse ); begin if UnWinControl =TEdit then else if UnWinControl=TMemo then ....etc end; procedure TwinEssai (UnWinControl : TWinControl); begin if UnWinControl is TEdit then else if UnWinContro is TMemo then ....etc end;

A comparer avec l'utilisation de l'oprateur is sur le mme problme

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

475

En passant un constructeur un paramtre de mta-classe on peut alors construire des objets dont la classe ne sera connue que lors de l'excution.

O dclarer une classe en Delphi ?


Les classes sont dclares dans des unit. Toutes les classes dclares dans la mme unit sont amies, c'est dire que chacune d'elle a accs aux membres privs de toutes les autres classes declares dans cette unit. Si l'on souhaite avoir n classes non amies, il faut les dclarer chacune dans une unit spare.

3.4 Le modle objet de Delphi Le modle physique choisi pour Delphi est celui de la rfrence : Chaque objet est caractris par un couple ( rfrence, bloc de donnes). Si la variable de rfrence est locale une procdure,elle est alors situe physiquement dans la pile dexcution avec les autres variables locales. Si la variable de rfrence est globale, elle est situe physiquement dans le segment de donnes (permanent durant toutes la dure de l'excution). Dans les deux cas, le bloc de donnes (l'objet effectif) est allou dans le tas. Ci-dessous une carte mmoire fictive d'un processus (une application Delphi classique un seul thread):

La simplicit du modle (semblable aux variables dynamiques ou pointeurs du pascal) permet de dire quen Delphi les pointeurs sont sous-jacents mais entirement encapsuls.
Ce modle impose une contrainte dcriture en dcouplant la dclaration dobjet et sa cration.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

476

3.5 Les objets en Delphi Un objet Delphi suit trs exactement les dfinitions gnrales d'objets. Un objet Delphi est une instance d'une classe. Un objet Delphi contient des membres qui sont : des variables pascal (champs ou attributs) des procdures et des fonctions (mthodes) des proprits. Nous verrons plus loin que ces proprits peuvent tre de diffrentes catgories, en premire lecture nous dirons que ce sont des champs possdant des spcificateurs d'accs.
clA = class private x : integer ; y : real ; Obj : clA ; procedure P1 (var a: integer); function F1 (a integer): char; function F2 : integer; public a , b : integer ; D : clA ; procedure P2 ; function F3 : boolean; property pr:real read y write y ; property ch:char read F1 ; end;

Les classes et les objets sont dclars dans les units (dans la partie dclaration de l'interface ou de l'implementation de l'unit), le code des mthodes est dfini uniquement dans la partie implementation de l'unit.

Constructeur / Destructeurs d'objets


En Delphi, chaque variable d'instance (objet instanci) doit obligatoirement tre initialise et peut tre dtruite lorsqu'elle n'est plus utile. Tout objet doit tre d'abord construit avant son utilisation. Ceci se fait l'aide d'une mthode spcifique dclare par le mot clef constructor. La destruction d'une instance s'effectue par une mthode aux proprits identiques un constructor et elle se dnomme un destructor.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

477

Par dfaut les classes disposent (provenant de la classe mre TObject) d'une mthode permettant la construction des objets de la classe : cette mthode de type constructor est dnomme Create. Ce genre de mthode assure la cration de l'objet physique en mmoire et sa liaison avec l'identificateur dclar dans le code (l'identificateur contient aprs l'action du Create, l'adresse physique de l'objet). Il en est de mme pour la dsallocation des objets de vos classes (leur destruction), celles-ci disposent d'un destructeur d'objets dnomm Destroy. Cette mthode de type destructor rend au processus, tout l'espace mmoire utilis par l'objet physique, mais attention elle ne drfrence pas l'identificateur, si ncessaire cette opration est la charge du programmeur (grce l'instruction : identificateur:=nil).

Unit Uclasses contenant une classe clA Unit Uclasses ; Interface type clA = class private x : integer ; y : real ; Obj : clA ; procedure P1 (var a: integer); function F1 (a integer): char; function F2 : integer; public a , b : integer ; D : clA ; procedure P2 ; function F3 : integer; property prop1: integer read x write x ; property prop2 : char read F1 ; end; implementation

Programme principal utilisant Uclasses Program principal ; Uses Uclasses ; procedure utilise (ObjA : clA); begin if ObjA.a > 5 then begin ObjA.P2 ; ObjA.b := end else prop1 := ObjA.a -1 end; var refA : clA ; Dclaration d'une rfrence de type clA. Instanciation d'un objet de type clA. ObjA.F3 - ObjA.a +1;

procedure clA.P1 (var a: integer); function clA.F1 (a integer): char; function clA.F2 : integer; procedure clA.P2 ; function clA.F3 : boolean; end.

begin refA : = clA.Create ; utilise ( refA ) ; refA.destroy; end.

Destruction de l'objet de type clA.

var refA : clA ; Lors de la dclaration une variable refA vide est cre : 98752 refA := clA.create refA : = clA.Create ; clA.Create

Lors de l'instanciation, un objet de type clA est cr dans le tas, puis sa rfrence (son adresse 98752) est mise dans la variable refA :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

478

refA.destroy; Lors de la destruction , l'objet du tas est dtruit, la mmoire qu'il occupait est rendu au tas et la variable refA ne rfrence plus un objet.

Le paramtre implicite self

Etant donne une classe quelconque, chaque mthode de cette classe possde systmatiquement dans son implmentation un paramtre implicite dnomm Self, que vous pouvez utiliser. Cet identificateur Self dsigne l'objet (lorsqu'il sera instanci)dans lequel la mthode est appele.

Exemple: Unit Uclasses; Interface type clA = class private Obj : clA ; public x , y : integer ; a , b : integer ; function F1 : integer; end; implementation function clA.F1 : integer; begin self.a := self.x +2; result := self.a; end;

Program principal ; Uses Uclasses ; var refA : clA ; n : integer; begin refA : = clA.Create ; .

end.

refA.F1
end.

Lors de l'instanciation (refA : = clA.Create ) la valeur 98752 de la rfrence, est passe automatiquement dans la variable implicite self de chaque mthode de l'objet refA, ce qui a pour rsultat que dans la mthode F1, les expressions formelles self.a et self.x prennent une valeur effective et dsignent les valeurs effectives des champs a et x de l'objet n 98752 du tas.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

479

3.6 Encapsulation Rappelons que pratiquement, en POO l'encapsulation permet de masquer les informations et les oprations d'un objet aux autres objets. Contrairement certains autres langages orients objet, dans Delphi par dfaut, sil ny a pas de descripteur dencapsulation, tout est visible (donc public). Delphi possde au moins quatre niveaux d'encapsulation des informations dans un objet qui sont matrialiss par des descripteurs : published : Les informations sont accessibles par toutes les instances de toutes les classes (les clients) + accessibles l'inspecteur d'objet de Delphi. public : Les informations sont accessibles par toutes les instances de toutes les classes (les clients). protected : Les informations ne sont accessibles qu' toutes les instances de la classe elle-mme et toutes celles qui en hritent (ses descendants). private : Les informations ne sont accessibles qu' toutes les instances de la classe elle-mme.

3.7 Hritage Il s'agit en Delphi de l'hritage simple (graphe arborescent) dans lequel une famille drive d'une seule classe de base. Voici une partie du graphe d'hritage simple de certaines classes de Delphi :

Syntaxe de la dclaration d'hritage : Type classe_fille = class(classe_ancetre)

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

480

Type classe_ancetre = class { champs } { mthodes } end;

Type classe_fille = class(classe_ancetre) { champs } { mthodes } end;

Nous indiquons donc ainsi en Delphi que la classe_fille hrite de la classe_ancetre.


Nous avons vu que les deux dclarations ci-dessous taient quivalentes :

Type ma_classe = class {dclarations de champs } {spcification mthodes } {spcification proprits } end;

Type ma_classe = class(TObject) {dclarations de champs } {spcification mthodes } {spcification proprits } end;

L'criture de gauche indique en fait que toutes les classes dclares sans qualificatif d'hritage hritent automatiquement de la classe TObject. La VCL de Delphi est entirement construite par hritage (une hirarchie objet complte) partir de TObject. Ci-dessous la dclaration de la classe TObject dans Delphi :
TObject = class constructor Create; procedure Free; class function InitInstance(Instance: Pointer): TObject; procedure CleanupInstance; function ClassType: TClass; class function ClassName: ShortString; class function ClassNameIs(const Name: string): Boolean; class function ClassParent: TClass; class function ClassInfo: Pointer; class function InstanceSize: Longint; class function InheritsFrom(AClass: TClass): Boolean; class function MethodAddress(const Name: ShortString): Pointer; class function MethodName(Address: Pointer): ShortString; function FieldAddress(const Name: ShortString): Pointer; function GetInterface(const IID: TGUID; out Obj): Boolean; class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry; class function GetInterfaceTable: PInterfaceTable; function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; virtual; procedure AfterConstruction; virtual; procedure BeforeDestruction; virtual; procedure Dispatch(var Message); virtual; procedure DefaultHandler(var Message); virtual; class function NewInstance: TObject; virtual; procedure FreeInstance; virtual; destructor Destroy; virtual; end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

481

La classe Tobject utilise ici la notion de mthode de classe :

Une mthode de classe est une mthode (autre qu'un constructeur) qui agit sur des classes et non sur des objets.

La dfinition d'une mthode de classe doit commencer par le mot rserv class. Par exemple dans Tobject : TObject = class ... class function ClassName: ShortString; class function ClassParent: TClass; ...

La dclaration de dfinition d'une mthode de classe doit galement commencer par class : class function TObject.ClassName: ShortString; begin //...le paramtre self est ici la classe Tobject end; etc...

Outre la classe TObject, Delphi fournit le type de mta-classe (rfrence de classe) gnrale TClass : TClass = class of TObject;

3.8 surcharge de mthode Signature d'une mthode -- dfinition C'est son nom , le nombre et le type de ses paramtres On dit qu'une mthode est surcharge dans sa classe si l'on peut trouver dans la classe plusieurs signatures diffrentes de la mme mthode. En Delphi, les en-ttes des mthodes surcharges de la mme classe, doivent tre suivies du qualificateur overload afin d'indiquer au compilateur qu'il s'agit d'une autre signature de la mme mthode.
Dans la classe classeA nous avons dclar 3 surcharges de la mme mthode Prix, qui pourrait valuer un prix en fonction du montant rentr selon trois types de donnes exprimes en yen, en euro ou en dollar. Type classeA = class public function Prix(x:yen) : real;overload; function Prix(x:euro): real;overload; function Prix(x:dollar) : real;overload; end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

482

Comment appeler une surcharge de mthode ?


Soit le programme de droite qui utilise la classeA dfinie gauche avec 3 surcharges de la mthode Prix Unit Uclasses ; Program principal ; Uses Uclasses ; interface Type yen = class end; euro = class end; dollar = class end; classeA = class public function Prix(x:yen) : real;overload; function Prix(x:euro): real;overload; function Prix(x:dollar) : real;overload; end; implementation function classeA.Prix(x:yen) : real; // signature n1 begin end; function classeA.Prix(x:euro): real; begin end; function classeA.Prix(x:dollar) : real; begin end; var refA : classeA; a : yen ; b : euro ; c : dollar ; Procedure Calcul1 (ObjA : classeA; valeur : yen ); begin ObjA.Prix ( valeur) end; Procedure Calcul2 (ObjA : classeA; valeur : euro); begin ObjA.Prix ( valeur ) end; Procedure Calcul3 (ObjA : classeA; valeur : dollar); Var ObjA : classeA ; begin Le compilateur connat ObjA.Prix ( valeur) le type du second end; paramtre, lorsqu'il appelle : begin refA:= classeA.Create ; ObjA.Prix ( valeur ) a := yen.Create ; Il va alors chercher s'il b := euro.Create ; existe une signature c := dollar.Create ; correspondant ce type Calcul1 ( refA , a ); et va excuter le code de Calcul2 ( refA , b ); la surcharge adquate Calcul3 ( refA , c ); End.

L'appel ObjA.Prix(valeur) dans Calcul1( refA , a ) sur a de type yen provoque la recherche de la signature suivante Prix ( type yen), c'est la signature n1 qui est trouve et excute. L'appel ObjA.Prix(valeur) dans Calcul2( refA , b ) sur a de type euro provoque la recherche de la signature suivante Prix ( type euro) ), c'est la signature n 2 qui est trouve et excute. L'appel ObjA.Prix(valeur) dans Calcul3( refA , c ) sur a de type dollar provoque la recherche de la signature suivante Prix ( type dollar) ), c'est la signature n3 qui est trouve et excute.

4. Les proprits en Delphi


Une proprit dfinie dans une classe permet d'accder certaines informations contenues dans les objets instancis partir de cette classe. Une proprit a la mme syntaxe de dfinition et d'utilisation que celle d'un champ d'objet (elle possde un type de dclaration), mais en fait elle peut invoquer une ou deux mthodes internes pour fonctionner ou se rfrer directement un champ. Les mthodes internes sont dclares l'intrieur d'un bloc de dfintion de la proprit.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

483

Nous nous limiterons aux proprits non tableau, car cette notion est commune d'autres langages (C# en particulier) 4.1. Dfinition Comme un champ, une proprit dfinit un attribut d'un objet. Mais un champ n'est qu'un emplacement de stockage dont le contenu peut tre consult et modifi, tandis qu'une proprit peut associer des actions spcifiques la lecture et lors de la modification de ses donnes : une proprit peut tre utilise comme un attribut. Les proprits proposent un moyen de contrler l'accs aux attributs d'un objet et autorisent ou non le calcul sur les attributs. Syntaxe : property nomProprit[indices] : type [index constanteEntire] spcificateurs ;

Remarque : il faut au minimum un descripteur (ou spcificateur) d'accs pour une proprit :

soit lecture seule (spcificateur read), soit criture seule (spcificateur write), soit lecture et criture read . write .

Attention : Une proprit ne peut pas tre transmise comme paramtre rfrence dans une procdure ou une mthode ! Exemple de syntaxe d'criture de proprits :
classeA = class public property prop1 : integer read y write z ; // lecture et criture property prop2 : char read F1 ; // lecture seule property prop3 : string write t ; // criture seule end;

4.2. Accs par read/write aux donnes d'une proprit Aprs les spcificateurs read et write, il obligatoire de prciser le moyen d'accs la proprit : Ce moyen peut tre un attribut, ou une mthode.

Accs une proprit par un attribut


property proprit1: type read Fproprit1 ;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

484

La property proprit1 fait rfrence l'attribut Fproprit1 et en permet l'accs en lecture seule. Pour avoir un intrt, la property proprit1 doit tre dclare en public, tandis que l'attribut Fproprit1 est dclar en private. Lorsque la proprit est dfinie, il faut que le champ auquel elle se rfre ait dj t dfini dans la classe, ou dans une classe anctre. D'une faon gnrale on peut comparer la lecture et l'criture dans un champ et dans une proprit comme ci-dessous : Soit la classe classeA :
classeA = class public champ : integer ; end;

Soit une autre version de la classe classeA :


classeA = class private Fchamp : integer ; public property propr1 : integer read Fchamp write Fchamp ; end;

On peut donc assimiler la proprit propr1 une clef ouvrant une porte sur un champ priv de l'objet. et autorisant la lecture et/ou l'criture dans ce champ.
Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

485

Exemple d'utilisation :

Accs une proprit par une mthode


Cas du spcificateur d'accs read

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

486

La mthode d'accs en lecture LireProp1 doit :


tre une fonction, tre sans paramtres, renvoyer un rsultat du mme type que celui de la proprit.

Cas du spcificateur d'accs write

La mthode d'accs en criture EcririreProp1 doit :


tre une procdure, n'avoir qu'un seul paramtre formel pass par constante ou par valeur (pas par rfrence), ce paramtre doit tre du mme type que celui de la proprit.

4.4 Surcharge de proprits


Surcharge permettant d'augmenter la visibilit

Lorsqu'une proprit est dclare dans une classe, on peut la surcharger dans les classes drives en augmentant son niveau de visibilit.
MaClasse = class private Fchamp : integer ; protected property propr1 : integer read Fchamp write Fchamp ; end; MaFille = class (MaClasse) private Fchamp : integer ; public property propr1 : integer read Fchamp write Fchamp ; end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

487

Surcharge permettant de redfinir un spcificateur existant

On ne peut pas supprimer de spcificateur. Par contre on peut modifier le/les spcificateur(s) existant(s) ou ajouter le spcificateur manquant.
MaClasse = class private Fchamp : integer ; public property propr1 : integer read Fchamp ; property propr2 : integer read Fchamp ; end; MaFille = class (MaClasse) private Fchamp : integer ; function lirePropr2 : integer ; public property propr1 : integer read Fchamp write Fchamp ; property propr2 : integer read lirePropr2 ; end;

Redfinition et masquage d'une proprit

Une proprit redfinie dans une classe remplace l'ancienne avec ses nouveaux attributs, son nouveau type.
MaClasse = class private Fchamp : integer ; protected property propr1 : integer read Fchamp write Fchamp ; end; MaFille = class (MaClasse) private FNom : string ; public property propr1 : string read Fnom ; end;

Ds qu'une redclaration de proprit contient une redfinition de type, elle masque automatiquement la proprit parent hrite et la remplace entirement. Elle doit donc tre redfinie avec au moins un spcificateur d'accs.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

488

5.3 Polymorphisme avec Delphi

Plan de ce chapitre: Polymorphisme d'objet


Introduction Instanciation et utilisation dans le mme type Instanciation et utilisation dans un type diffrent Polymorphisme implicite Instanciation dans un type descendant Polymorphisme explicite par transtypage Utilisation pratique du polymorphisme d'objet instanciation dans un type ascendant

Polymorphisme de mthode

Introduction Vocabulaire et concepts Surcharge dans la mme classe Surcharge dans une classe drive Surcharge dynamique dans une classe drive Rpartition des mthodes en Delphi Rutilisation de mthodes avec inherited

Polymorphisme de classe abstraite


Introduction Vocabulaire et concepts

Exercice trait sur le polymorphisme

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

489

1. Polymorphisme d'objet
Conversion de rfrences d'objet entre classe et classe drive

Il existe un concept essentiel en POO dsignant la capacit d'une hirarchie de classes fournir diffrentes implmentations de mthodes portant le mme nom et par corollaire la capacit qu'ont des objets enfants de modifier les comportements hrits de leur parents. Ce concept d'adaptation diffrentes "situations" se dnomme le polymorphisme qui peut tre implment de diffrentes manires.

Polymorphisme d'objet - dfinition gnrale


C'est une interchangeabilit entre variables d'objets de classes de la mme hirarchie sous certaines conditions, que dnommons le polymorphisme d'objet.

Soit une classe Mere et une Fille hritant de la classe Mere :

Les objets peuvent avoir des comportements polymorphes (s'adapter et se comporter diffremment selon leur utilisation) licites et des comportements polymorphes dangereux selon les langages. Dans un langage dont le modle objet est la rfrence (un objet est un couple : rfrence, bloc mmoire) comme C++, C#, Delphi ou Java, il y a dcouplage entre les actions statiques du compilateur et les actions dynamiques du systme d'excution selon le langage utilis le compilateur protge ou non statiquement des actions dynamiques sur les objets une fois crs. C'est la dclaration et l'utilisation des variables de rfrences qui autorise ou non les actions licites grce la compilation. Supposons que nous ayons dclar deux variables de rfrence, l'une de classe Mere, l'autre de classe Fille, une question qui se pose est la suivante : au cours du programme quel genre d'affectation et d'instanciation est-on autoris effectuer sur chacune de ces variables. L'hritage permet une variabilit entre variables d'objets de classes de la mme hirarchie, c'est cette variabilit que dnommons le polymorphisme d'objet. Nous allons ds lors envisager toutes les situations possibles et les valuer, les exemples appuyant le texte sont prsents en Delphi.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

490

instanciation dans le type initial et utilisation dans le mme type


Il s'agit ici d'une utilisation la plus classique qui soit, dans laquelle une variable est utilise dans son type de dfinition initial.

var x,u : Mere; y,v : Fille ; ..... x : = Mere.Create ; // instanciation dans le type initial u := x; // affectation de rfrences du mme type y : = Fille.Create ; // instanciation dans le type initial v := y; // affectation de rfrences du mme type

instanciation dans le type initial et utilisation diffrente


Il s'agit ici de l'utilisation licite commune tous les langages cits plus haut, nous illustrons le discours en explicitant deux champs de la classe Mere (chm:chaine et a:entier) et un champ supplmentaire (chf:chaine) dans la classe Fille. il existe 3 possibilits diffrentes, la figure ci-dessous indique les affectations possibles :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

491

var x , ObjM : Mere; y , ObjF : Fille; ObjM := Mere.Create; // instanciation dans le type initial ObjF := Fille.Create; // instanciation dans le type initial x := ObjM; // affectation de rfrences du mme type x := ObjF; // affectation de rfrences du type descendant implicite y := ObjF; // affectation de rfrences du mme type y := Fille(ObjM); // affectation de rfrences du type ascendant explicite mais dangereux si ObjM
est uniquement Mere Les trois possibilits sont :

L'instanciation et l'utilisation de rfrences dans le mme type L'affectation de rfrences : polymorphisme implicite L'affectation de rfrences : polymorphisme par transtypage d'objet

La dernire de ces possibilits pose un problme d'excution lorsqu'elle est mal employe !

Polymorphisme d'objet implicite


Dans l'exemple prcdent le compilateur accepte le transtypage 'y :=Fille(ObjM)' car il autorise un polymorphisme d'objet de classe ascendante vers une classe descendante (c'est dire que ObjM peut se rfrer implicitement tout objet de classe Mere ou de toute classe descendante de la classe Mere).

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

492

Nous pouvons en effet dire que x peut se rfrer implicitement tout objet de classe Mere ou de toute classe hritant de la classe Mere :

fig - 1 fig - 2

Dans la figure fig-1 ci-dessus, une hirarchie de classes decendant toutes de la classe Mere. Dans la figure fig-2 ci-dessus le schma montre une rfrence de type Mere qui peut 'pointer' vers n'importe quel objet de classe descendante (polymorphisme d'objet).

Exemple pratique tir du schma prcdent Le polymorphisme d'objet est typiquement fait pour reprsenter des situations pratiques figures ci-dessous : (Mere=vehicule, Fille1=terrestre, Fille2=voiture, Fille3=marin, Fille4=voilier, Fille5=croiseur)

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

493

Une hirarchie de classes de vhicules descendant toutes de la classe mre Vehicule. Dclaration de cette hirarchie en
Marin = class (Vehicule) .......... end; voilier = class (marin) .......... end; croiseur = class (marin) .......... end;

Vehicule = class .......... end; terrestre = class (Vehicule) .......... end; voiture = class (terrestre) .......... end;

On peut noncer le fait qu'un vhicule peut tre de plusieurs sortes : soit un croiseur, soit une voiture, soit un vhicule terrestre etc... En traduisant cette phrase en termes informatiques : Si l'on dclare une rfrence de type vhicule (var x : vehicule) elle pourra pointer vers n'importe quel objet d'une des classe filles de la classe vehicule. Polymorphisme implicite = cration d'objet de classe descendante rfrenc par une variable parent

Quand peut-on crire x := y sur des objets ?


D'une faon gnrale vous pourrez toujours crire des affectations entre deux rfrences d'objets :

var x : Classe1 y : Classe2 .......... x := y; si et seulement si Classe2 est une classe descendante de Classe1.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

494

instanciation dans un type descendant


Polymorphisme par cration d'objet de classe descendante Dans ce paragraphe nous signalons qu'il est tout fait possible, du fait du transtypage implicite, de crer un objet de classe descendante rfrenc par une variable de classe parent.

Ajoutons 2 classes la hirarchie des vhicules :

La nouvelle hirarchie est la suivante :

Ensuite nous dclarons 3 rfrences de type x:vehicule, y:voiture et z:break , puis nous crons 3 objets de classe voiture, berline et break, il est possible de crer directement un objet de classe descendante partir d'une rfrence de classe mre : on cre une voiture rfrence par la variable x de classe vehicule, on cre une berline rfrence par la variable y de classe voiture, enfin on cre un break rfrenc par la variable z de classe break.

Rcrivons ces phrases afin de comprendre quel genre de situation pratique cette opration correspond :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

495

on cre un vhicule du type voiture on cre une voiture de type berline enfin on cre un break de type break

var x : vehicule; y : voiture; z : break; ... x := voiture.Create; // objet de classe enfant voiture rfrenc par x de classe parent vehicule y := berline.Create; // objet de classe enfant berline rfrenc par x de classe parent voiture z := break.Create; // instanciation dans le type initial

Polymorphisme d'objet explicite par transtypage


Reprenons le code prcdent en extrayant la partie qui nous intresse : var x , ObjM : Mere; y : Fille; ObjM := Mere.Create; // instanciation dans le type initial x := ObjM; // affectation de rfrences du mme type y := Fille(ObjM); // affectation de rfrences du type ascendant explicite licite Nous avons signal que l'affectation y := Fille(ObjM) pouvait tre dangereuse si ObjM pointe vers un objet purement de type Mere. Voyons ce qu'il en est. Nous avons vu plus haut qu'une rfrence de type parent peut 'pointer' vers n'importe quel objet de classe descendante. Si l'on sait qu'une refrence x de classe parent, pointe vers un objet de classe enfant, on peut en toute suret procder une affectation de cette refrence une autre refrence y dfinie comme refrence classe enfant ( opration y := x ). La situation informatique est la suivante :

on dclare une variable x de type Mere, on dclare une variable y de type Fille hritant de Mere, on instancie la variable x dans le type descendant Fille (polymorphisme implicite).

Il est alors possible de faire "pointer" la variable y (de type Fille) vers l'objet (de type Fille) auquel se rfre x en effectuant une affectation de rfrences. Toutefois le compilateur refusera l'criture y := x, il suffit de lui indiquer qu'il faut

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

496

transtyper la variable de rfrence x et la considrer dans cette instruction comme une refrence sur un enfant var x : Mere; y : Fille; x := Mere.Create; // instanciation dans le type initial y := Fille(ObjM); // affectation de rfrences du type ascendant explicite licite Dans la dernire instruction, la refrence ObjM est transtype en type Fille, de telle manire que le compilateur puisse faire pointer y vers l'objet dj point par ObjM. En reprenant l'exemple pratique de la hirarchie des vhicules :

Puisque x pointe vers un objet de type voiture toute variable de rfrence voiture acceptera de pointer vers cet objet, en particulier la variable y :voiture aprs transtypage de la rfrence de x. var x : vehicule; y : voiture; ... x := voiture.Create; // objet de classe enfant voiture rfrenc par x de classe parent vehicule y := voiture ( x ); // transtypage En Delphi l'affectation s'crit par application de l'oprateur de transtypage :

y := voiture ( x );

ATTENTION
La validit du transtypage n'est pas vrifie statiquement par le compilateur, donc si votre variable de rfrence pointe vers un objet qui n'a pas la mme nature que l'oprateur de transtypage, c'est de l'excution qu'il y aura production d'un message d'erreur indiquant le transtypage impossible. Il est donc impratif de tester l'appartenance la bonne classe de l'objet transtyper avant de le transtyper, les langages C#, Delphi et Java disposent d'un oprateur permettant de tester cette appartenance ou plutt l'appartenance une hirarchie.

L'oprateur "is" en

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

497

L'oprateur is, qui effectue une vrification de type dynamique, est utilis pour vrifier quelle est effectivement la classe d'un objet l'excution.

L'expression : objet is classeT


renvoie True si objet est une instance de la classe dsigne par classeT ou de l'un de ses descendants, et False sinon. Si objet a la valeur nil, le rsultat est False.

L'oprateur "as" en
L'oprateur as est un oprateur de transtypage de rfrence d'objet semblable l'oprateur ( ). L'oprateur as fournit la valeur null en cas d'chec de conversion alors que l'oprateur ( ) lve une exception.

(objet as classeT) renvoie une rfrence de type classeT Exemple d'utilisation des deux oprateurs : var x : classeT; if objet is classeT then x := objet as classeT ;

Utilisation pratique du polymorphisme d'objet


Le polymorphisme d'objet associ au transtypage est trs utile dans les paramtres des mthodes. Lorsque vous dclarez une mthode P avec un paramtre formel de type ClasseT :
procedure P( x : ClasseT ); begin ........ end;

Vous pouvez utiliser lors de l'appel de la procdure P n'importe quel paramtre effectif de ClasseT ou bien d'une quelconque classe descendant de ClasseT et ensuite l'intrieur de la procdure vous transtypez le paramtre. Cet aspect est abondamment utilis en Delphi lors de la cration de gestionnaires d'vnements communs plusieurs objets :
procedure P1( Sender : Tobject ); begin if Sender is TEdit then TEdit(Sender).text := 'ok' else if Sender is TButton then TButton(Sender).caption := 'oui' ............ end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

498

Autre exemple avec une mthode P2 personnelle sur la hirarchie des vhicules dfinies plus haut :
procedure P2( Sender : vehicule ); begin if Sender is voiture then voiture(Sender). ....... else if Sender is voilier then voilier(Sender). ....... ............ end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

499

2. Polymorphisme de mthode
Introduction
Lorsqu'une classe enfant hrite d'une classe mre, des mthodes supplmentaires nouvelles peuvent tre implmentes dans la classe enfant mais aussi des mthodes des parents redfinies pour obtenir des implmentations diffrentes. Une classe drive hrite de tous les membres de sa classe parent ; c'est--dire que tous les membres du parent sont disponibles pour l'enfant, rappelons qu'une mthode est un membre qualifiant un comportement d'un objet de la classe. En POO on distingue deux catgories de mthodes selon les besoins des applications et du polymorphisme : les mthodes statiques et les mthodes dynamiques.

2.1 Vocabulaire et concepts gnraux :

L'action qui consiste donner le mme nom plusieurs mthodes dans la mme classe ou d'une classe parent une classe enfant, se dnomme d'une manire gnrale la surcharge de nom de mthode (avec ou non la mme signature). Le vocabulaire n'tant pas stabilis selon les auteurs (surcharge, redfinition, substitution,...) nous employerons les mots redfinition, surcharge dynamique ou substitution dans le mme sens, en prcisant lorsque cela s'avrera ncessaire de quel genre de laison il s'agit.

Les actions des mthodes hrites du parent peuvent tre modifis par l'enfant de deux manires, selon le type de liaison du code utilis pour la mthode (la liaison statique ou prcoce ou bien la liaison dynamique ou retarde).

Les deux modes de liaison du code d'une mthode


La liaison statique ou prcoce (early-binding) : Lorsqu'une mthode liaison statique est invoque dans le corps d'un programme, le compilateur tablit immdiatement dans le code appelant l'adresse prcise et connue du code de la mthode invoquer. Lors de l'excution c'est donc toujours le mme code invoqu. La liaison dynamique ou retarde (lazy-binding) : Lorsqu'une mthode liaison dynamique est invoque dans le corps d'un programme, le compilateur n'tablit pas immdiatement dans le code appelant l'adresse de la mthode invoquer. Le compilateur met en place un mcanisme de refrence (rfrence vide lors de la compilation) qui, lors de l'excution, dsignera (pointera vers) le code que l'on voudra invoquer; on pourra donc invoquer des codes diffrents.

2.2 Surcharge dans la mme classe :


Dans une classe donne, plusieurs mthodes peuvent avoir le mme nom, mais les signatures des mthodes ainsi surcharges doivent obligatoirement tre diffrentes et peuvent ventuellement avoir des niveaux de visibilit diffrents.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

500

Nous avons dj vu les bases de ce type de surcharge lors de l'tude de Delphi et la POO. Soit par exemple, la classe ClasseA ci-dessous, ayant 3 mthodes de mme nom P, elles sont surcharges dans la classe selon 3 signatures diffrentes :
Classe A public methode P(x,y); priv methode P(a,b,c); protg methode P( ); finClasse A

La premire surcharge de P dispose de 2 paramtres, la seconde de 3 paramtres, la dernire enfin n'a pas de paramtres. C'est le compilateur du langage qui devra faire le choix pour slectionner le code de la bonne mthode utiliser. Pour indiquer ce genre de surcharge, en Delphi il faut utiliser un qualificateur particulier dnot overload.
Syntaxe de l'exemple en Delphi, en Java et en C# : Delphi ClasseA = class public procedure P(x,y : integer);overload; private procedure P(a,b,c : string); overload; protected procedure P;overload; end; Java - C# class ClasseA { public void P( int x,y ){ } private void P( String a,b,c ){ } protected void P( ){ } }

Utilisation pratique : permettre une mthode d'accepter plusieurs types de paramtres en conservant le mme nom, comme dans le cas d'oprateur arithmtique travaillant sur les entiers, les rels,... Exemple de code Delphi :
ClasseA = class public procedure P(x,y : integer);overload; procedure P(a,b,c : string);overload; procedure P;overload; end; var Obj:ClasseA; ..... Obj := ClasseA.create; Obj.P( 10, 5 ); Obj.P( 'abc', 'ef', 'ghi' ); Obj.P;

2.3 Surcharge statique dans une classe drive :


D'une manire gnrale, Delphi et C# disposent par dfaut de la notion de mthode statique, Java n'en dispose pas sauf dans le cas des mthodes de classes. Dans l'exemple ci-dessous en Delphi et en C#, les trois mthodes P,Q et R sont liaison statique dans leur dclaration par dfaut sans utiliser de qualificateur spcial.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

501

Delphi ClasseA = class public procedure P(x,y : integer); private procedure Q(a,b,c : string); protected procedure R; end;

C# class ClasseA { public void P( int x,y ){ } private void Q( String a,b,c ){ } protected void R( ){ } }

Une classe drive peut masquer une mthode liaison statique hrite en dfinissant une nouvelle mthode avec le mme nom.

Si vous dclarez dans une classe drive, une mthode ayant le mme nom qu'une mthode liaison statique d'une classe anctre, la nouvelle mthode remplace simplement la mthode hrite dans la classe drive. Dans ce cas nous employerons aussi le mot de masquage qui semble tre utilis par beaucoup d'auteurs pour dnommer ce remplacement, car il correspond bien l'ide d'un masquage "local" dans la classe fille du code de la mthode de la classe parent par le code de la mthode fille.

Ci-dessous un exemple de hirarchie de classes et de masquages successifs licites de mthodes liaison statiques dans certaines classes drives avec ou sans modification de visibilit :
Classe A public statique methode P; priv statique methode Q; protg statique methode R; finClasse A Classe D hrite de Classe C public statique methode P; Classe B hrite de Classe A public statique methode P; priv statique methode Q; protg statique methode R; finClasse B Classe E hrite de Classe D protg statique methode P; Classe C hrite de Classe B protg statique methode P; priv statique methode Q; finClasse C Classe F hrite de Classe E priv statique methode P; public statique methode R; finClasse F

finClasse D

finClasse E

Dans le code d'implmentation de la Classe F :


La mthode P utilise est celle qui dfinie dans la Classe F et elle masque la mthode P de la Classe E. La mthode Q utilise est celle qui dfinie dans la Classe C. La mthode R utilise est celle qui dfinie dans la Classe F et elle masque la mthode R de la Classe B

Soit en Delphi l'criture des classes ClasseA et ClasseB de la hirarchie ci-haut :


Delphi ClasseA = class public procedure P(x,y : integer); private procedure Q(a,b,c : string); protected procedure R; end; Explications Dans la classe ClasseB : La mthode procedure P(u : char) surcharge statiquement (masque) avec une autre signature, la mthode hrite de sa classe parent procedure P(x,y : integer).

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

502

ClasseB = class ( ClasseA ) public procedure P(u : char); private procedure Q(a,b,c : string); protected procedure R(x,y : real); end;

La mthode procedure Q(a,b,c : string) surcharge statiquement (masque) avec la mme signature, la mthode hrite de sa classe parent procedure Q(a,b,c : string). La mthode procedure R(x,y : real) surcharge statiquement (masque) avec une autre signature, la mthode hrite de sa classe parent procedure R.

Utilisation pratique : Possibilit notamment de dfinir un nouveau comportement li la classe descendante et ventuellement de changer le niveau de visibilit de la mthode. Exemple de code Delphi :
ClasseA = class public procedure P(x,y : integer); procedure Q(a,b,c : string); procedure R; end; ClasseB = class ( ClasseA ) public procedure P(u : char); procedure Q(a,b,c : string); procedure R(x,y : real); end; ........ ......... var ObjA:ClasseA; ObjB:ClasseB; ..... ObjA := ClasseA.create; ObjA.P( 10, 5 ); ObjA.Q( 'abc', 'ef', 'ghi' ); ObjA.R; ......... ObjB := ClasseB.create; ObjB.P( 'g' ); ObjB.Q( 'abc', 'ef', 'ghi' ); ObjB.R( 1.2, -5.36 );

2.4 Surcharge dynamique dans une classe drive :


Un type driv peut redfinir (surcharger dynamiquement) une mthode liaison dynamique hrite. On appelle aussi virtuelle une telle mthode liaison dynamique, nous utiliserons donc souvent ce raccourci de notation pour dsigner une mthode surchargeable dynamiquement. L'action de redfinition fournit une nouvelle dfinition de la mthode qui sera appele en fonction du type de l'objet au moment de l'excution et non du type de la variable de refrence connue au moment de la compilation.

Ci-dessous un exemple de hirarchie de classes et de redfinitions (surcharges dynamiques) successives fictives de mthodes liaison dynamique dans certaines classes drives, pour les modifications de visibilit il faut tudier le manuel de chaque langage :
Classe A public dynamique methode P; priv dynamique methode Q; protg dynamique methode R; finClasse A Classe D hrite de Classe C public dynamique methode P; finClasse D Classe B hrite de Classe A public dynamique methode P; priv dynamique methode Q; protg dynamique methode R; finClasse B Classe E hrite de Classe D protg dynamique methode P; finClasse E Classe C hrite de Classe B protg dynamique methode P; priv dynamique methode Q; finClasse C Classe F hrite de Classe E priv dynamique methode P; public dynamique methode R; finClasse F

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

503

Remarque pratique :
Une mthode redfinissant une mthode virtuelle peut selon les langages changer le niveau de visibilit ( il est conseill de laisser la nouvelle mthode redfinie au moins aussi visible que la mthode virtuelle parent).

Tableau comparatif liaison dynamique-statique

Liaison statique
Lors d'un appel pendant l'excution leur liaison est trs rapide car le compilateur a gnr l'adresse prcise du code de la mthode lors de la compilation. Une telle mthode fonctionne comme une procdure ou fonction d'un langage non orient objet et ne permet pas le polymorphisme. Car lors d'un appel pendant l'excution c'est toujours le mme code qui est excut quel que soit le type de l'objet qui l'invoque.

Liaison dynamique
Lors d'un appel pendant l'excution leur liaison plus lente car l'adresse prcise du code de la mthode est obtenu par un processus de recherche dans une structure de donnes. Une telle mthode autorise le polymorphisme, car bien que portant le mme nom dans une hirarchie de classe, lors d'un appel pendant l'excution c'est toujours le type de l'objet qui l'invoque qui dclenche le mcanisme de recherche du code adquat.

2.5 La rpartition des mthodes en Delphi


Le terme de rpartition des mthodes est synonyme de liaison et fait rfrence la faon dont un programme dtermine o il doit rechercher le code d'une mthode lorsqu'il rencontre un appel cette mthode. En Delphi, il existe trois modes de rpartition des mthodes qui peuvent tre : Statiques , Virtuelles, Dynamiques.

Mthodes statiques en Delphi


Les mthodes statiques de Delphi sont des mthodes liaison prcoce.
Dans SousClas nous avons 3 mthodes statiques : Un (celle de la mre) , Deux (celle de la mre), Trois (celle de la fille). Appel de Un de Var Obj : MaClasse ; Appel de Obj := SousClasse.Create ; MaClasse Deux de MaClasse Obj.Un ; Obj.Deux ; Appel de Obj.Trois ; Trois de sousClasse

type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; //statique end; SousClasse=class(MaClasse) procedure Trois; //statique end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

504

Voyons ce qui se passe lorsque dans la classe fille on tente de "redfinir" une mthode hrite de la classe mre. Ci-aprs nous tentons de "redfinir" la mthode Deux :
type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; //statique end; SousClasse=class(MaClasse) procedure Deux; //statique procedure Trois; //statique end; Dans SousClas nous avons 3 mthodes statiques : Un (celle de la mre) , Deux (celle de la mre), Trois (celle de la fille). Appel de Un de Var Obj : MaClasse ; Appel de Obj := SousClasse.Create ; MaClasse Deux de MaClasse Obj.Un ; Obj.Deux ; Appel de Obj.Trois ; Trois de sousClasse

Lors de l'excution de l'appel Obj.Deux, rien n'a chang. En effet lors de la compilation la variable Obj est dclare de type MaClasse, c'est donc l'adresse du code de la mthode Deux de la classe MaClasse qui est lie. Le type SousClasse de l'objet rel vers lequel pointe Obj pendant l'excution n'a aucune influence sur le mode de rpartition :

Important

Cela signifie qu'il est impossible de redfinir une mthode statique P; c'est toujours le mme code qui est excut, quelque soit la classe dans laquelle P est appele. Si l'on dclare dans une classe drive une mthode portant le mme nom qu'une mthode statique de la classe mre avec la mme signature ou bien avec une signature diffrente, la nouvelle mthode remplace simplement la mthode hrite dans la classe drive, nous dirons qu'elle masque la mthode mre.

Masquage avec la mme signature type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; //statique end; SousClasse=class(MaClasse) procedure Deux; // masque la mthode mre procedure Trois; //statique end; Var Obj : MaClasse ; Obj := SousClasse.Create ; Obj.Un ; Obj.Deux ; Obj.Trois ; Appel de Deux de MaClasse

Masquage avec une signature diffrente type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; //statique end; SousClasse=class(MaClasse) procedure Deux ( x : byte ) ; // masque la mthode mre procedure Trois; //statique end; Appel de Deux de Var Obj : MaClasse ; MaClasse Obj := SousClasse.Create ; Obj.Un ; Obj.Deux ; Obj.Trois ; Obj.Deux ( 49 ) ; Erreur de compilation ! car Obj est de type MaClasse et la signature Deux (byte) n'existe pas dans MaClasse.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

505

Mthodes virtuelles en Delphi


Les mthodes virtuelles utilisent un mcanisme de rpartition ncessitant une recherche contrairement aux mthodes statiques. Une mthode virtuelle peut tre redfinie dans les classes descendantes sans masquer ses diffrentes versions dans les classes anctres. A l'oppos d'une mthode statique l'adresse du code de la mthode virtuelle n'est pas dtermine lors de la compilation, mais seulement lors de l'excution et en fonction du type de l'objet qui l'appelle. Les mthodes virtuelles de Delphi sont des mthodes liaison tardive. Pour dclarer une mthode virtuelle, il faut ajouter le qualificateur virtual la fin de la dclaration de l'en-tte de la mthode :
procedure P(x,y : integer); virtual ;

Comment se passe la liaison dynamique avec Delphi ?


Delphi implante d'une faon classique le mcanisme de liaison dynamique :

Lors de la compilation, Delphi rajoute chaque classe une Table des Mthodes Virtuelles (TMV). Cette table contient en principal, pour chaque mthode dclare avec le qualificateur virtual : un pointeur sur le code de la mthode, la taille de l'objet lui-mme

Donc chaque objet possde sa propre TMV , et elle est unique. La TMV d'un objet est cre avec des pointeurs vides lors de la compilation, elle est remplie lors de l'excution du programme ( plus prcisment lors de l'instanciation de l'objet) car c'est l'excution que l'adresse du code de la mthode est connue et donc stocke dans la TMV. En fait c'est le constructeur de l'objet lors de son instanciation qui lance le stockage dans la TMV des adresses de toutes les mthodes virtuelles de l'objet, la fois les mthodes hrites et les mthodes nouvelles.

Lorsque l'on construit une nouvelle classe hritant d'une autre classe mre, la nouvelle classe rcupre dans sa TMV toutes les entres de la TMV de sa classe mre, plus les nouvelles entres correspondant aux mthodes virtuelles dclares dans la nouvelle classe. Une TMV est donc une structure de donnes qui grossit au cours de l'hritage de classe et peut tre assez volumineuse pour des objets de classes situes en fin de hirarchie.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

506

Redfinition de mthode virtuelle avec Delphi


Pour redfinir une mthode virtuelle dans les classes descendantes sans masquer ses diffrentes versions dans les classes anctres, il faut ajouter la fin de sa dclaration d'en-tte le qualificateur override. Reprenons l'exemple prcdent et tentons de "redfinir" la mthode Deux cette fois en la dclarant virtuelle dans la classe mre et redfinie dans la classe fille, puis comparons le comportement polymorphique de la mthode Deux selon qu'elle est virtuelle ou statique :
type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; virtual ; //virtuelle end; SousClasse=class(MaClasse) procedure Deux; override; //redfinie procedure Trois; //statique end; Dans SousClas nous avons 2 mthodes statiques : Un , Trois et une mthode virtuelle redfinie : Deux Var Obj : MaClasse ; Obj := SousClasse.Create ; Obj.Un ; Obj.Deux ; Obj.Trois ;

Appel de Deux de sousClasse

type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; //statique end; SousClasse=class(MaClasse) procedure Deux; //statique procedure Trois; //statique end;

Dans SousClas nous avons 3 mthodes statiques : Un (celle de la mre) , Deux (celle de la mre), Trois (celle de la fille). Var Obj : MaClasse ; Obj := SousClasse.Create ; Obj.Un ; Obj.Deux ; Obj.Trois ; Appel de Deux de MaClasse

Mthodes dynamiques en Delphi


Les mthodes dynamiques sont des mthodes virtuelles avec un mcanisme de rpartition diffrent, donc les mthodes dynamiques de Delphi sont des mthodes liaison tardive.

technique
Au lieu d'tre stockes dans la Table des Mthodes Virtuelles, les mthodes dynamiques sont ajoutes dans une structure de donnes de liste spcifique pour chaque objet (la liste des mthodes dynamiques). Seules les adresses des mthodes nouvelles ou redfinies d'une classe sont ranges dans sa liste.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

507

La liaison prcode d'une mthode dynamique hrite s'effectue en recherchant dans la liste des mthodes dynamiques de chaque anctre, en remontant la hirarchie de l'hritage. Pour dclarer une mthode dynamique, il faut ajouter le qualificateur dynamic la fin de la dclaration de l'en-tte de la mthode :
procedure P(x,y : integer); dynamic ;

Remarques de Borland

Toute mthode sans qualification particulire est considre comme statique par dfaut. Comme les mthodes dynamiques ne disposent pas d'entres dans la table des mthodes virtuelles de l'objet, elles rduisent la quantit de mmoire occupe par les objets. Si une mthode est appele frquemment, ou si le temps d'excution est un paramtre important, il vaut mieux dclarer une mthode virtuelle plutt que dynamique.

Masquage de mthode virtuelle avec Delphi


Pour masquer une mthode virtuelle dans une de ses classes, il suffit de ne pas ajouter la fin de sa dclaration d'en-tte le qualificateur override. Ceci peut se faire de deux faons soit en masquant par une mthode statique, soit en masquant par une mthode dynamique.

Masquage par une mthode dynamique


Dans le code suivant, la mthode Deux dclare virtuelle dans la classe mre, est masque par une mthode Deux ayant la mme signature et dclare elle aussi virtuelle dans la classe fille :
type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; virtual; //virtuelle end; SousClasse=class(MaClasse) procedure Un ; //statique, masque la mthode anctre procedure Deux;virtual; // virtuelle, masque la mthode anctre, mais elle-mme est redfinissable end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

508

comparons le comportement polymorphique de la mthode Deux selon qu'elle est redfinie, masque par une mthode statique ou masque par une mthode virtuelle :
type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; virtual ; //virtuelle end; SousClasse=class(MaClasse) procedure Deux; override; //redfinie procedure Trois; //statique end; Dans SousClas nous avons 2 mthodes statiques : Un , Trois et une mthode virtuelle redfinie : Deux Var Obj : MaClasse ; Obj := SousClasse.Create ; Obj.Un ; Obj.Deux ; Obj.Trois ;

Appel de Deux de sousClasse

type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; virtual ; //virtuelle end; SousClasse=class(MaClasse) procedure Deux; //masquage procedure Trois; //statique end; type MaClasse=class Etat:string; procedure Un; //statique procedure Deux; virtual ; //virtuelle end; SousClasse=class(MaClasse) procedure Deux; virtual ; //masquage procedure Trois; //statique end;

Dans SousClas nous avons 2 mthodes statiques : Un , Trois et une mthode virtuelle masque statiquement : Deux Var Obj : MaClasse ; Obj := SousClasse.Create ; Obj.Un ; Obj.Deux ; Obj.Trois ; Appel de Deux de MaClasse

Dans SousClas nous avons 2 mthodes statiques : Un , Trois et une mthode virtuelle masque virtuellemnt: Deux Var Obj : MaClasse ; Obj := SousClasse.Create ; Obj.Un ; Obj.Deux ; Obj.Trois ; Appel de Deux de MaClasse

Nous pouvons conclure de ce tableau de comparaison que le masquage (par une mthode statique ou virtuelle) ne permet jamais le polymorphisme.

Exemple pratique
Le polymorphisme de mthode offre la possibilit de conserver le mme nom de mthode dans une hirarchie de classe, afin de ne pas "surcharger" le cerveau de l'utilisateur. Les comportements seront diffrents selon le type d'objet utilis.

Par exemple l'action de Dmarrer dans une hirarchie de vhicules :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

509

Nous voyons bien que smantiquement parlant on peut dire qu'une voiture dmarre, qu'un voilier dmarre, qu'un croiseur dmarre, toutefois les actions internes permettant le comportement dmarrage ne sont pas les mmes.

Dmarrer dans la classe voiture : tourner la clef de contact, engager une vitesse,... Dmarrer dans la classe voilier : hisser les voiles, dgager la barre,... Dmarrer dans la classe croiseur : lancer les moteurs, modifier la barre,...

L'action Dmarrer est polymorphe (car elle s'adapte au type de vhicule qui l'excute). Pour traduire en Delphi, ce comportement polymorphe de l'action Dmarrer, nous allons utiliser une mthode virtuelle que nous redfinissons dans toutes les classes drives. Soit en Delphi l'criture de l'exemple de la hirarchie prcdente : Delphi
Vehicule = class public procedure Demarrer; virtual; //virtuelle end; Terrestre = class ( Vehicule ) ..... end; Voiture = class ( Terrestre ) public procedure Demarrer; override; //redfinie end; Marin = class ( Vehicule ) ..... end; Voilier = class ( Marin ) public procedure Demarrer; override; //redfinie end; Croiseur = class ( Marin ) public procedure Demarrer; override; //redfinie end;

Exemple de code d'utilisation :


Vehicule = class public procedure Demarrer; virtual; (1) end; Voiture = class ( Terrestre ) public procedure Demarrer; override; (2) end; ........ var Vehic1 : Vehicule; Auto1, Auto2 : Voiture; ..... Vehic1 := Vehicule.Create; //instanciation dans le type Auto1 := Voiture.Create; //instanciation dans le type Auto2 := Voiture.Create; //instanciation dans le type Vehic1.Demarrer; //mthode du type Vehicule (1) Auto1.Demarrer; //mthode du type Voiture (2) Auto2.Demarrer; //mthode du type Voiture (2) Vehic1 := Auto1; //pointe vers un objet de type hrit Vehic1.Demarrer; // polymorphisme l'uvre ici: (2) ......... Vehic1 := Voiture.Create; //instanciation un type hrit Vehic1.Demarrer; // polymorphisme l'uvre ici: (2)

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

510

Illustrons l'exemple prcdent avec une image de la partie de code gnr sur la mthode Demarrer et ensuite l'excution de ce code sur des objets effectifs. Nous avons numrot (1) et (2) les deux codes d'implantation de la mthode Demarrer dans la classe parent et dans la classe enfant :

Le code engendr contient des refrences vides

Lors de l'excution aprs mcanisme de rpartition selon le genre de liaison et le type de l'objet, les refrences pointent vers le code de la mthode du type effectif de l'objet.

2.6 Rutilisation de mthodes avec inherited


Le mot rserv inherited joue dans Delphi un rle particulier dans l'implmentation de comportements polymorphiques (il joue un rle semblable super dans java et base dans C#). Il ne peut qu'apparatre dans une dfinition de mthode avec ou sans identificateur la suite.

Si inherited prsent dans une methode P de la classeA est suivi par le nom d'une mthode Q, il reprsente un appel normal de la mthode Q, sauf que la recherche de la mthode invoquer commence dans l'anctre immdiat de la classe de la mthode et remonte la hirarchie. Si inherited prsent dans une methode P de la classeA, n'est suivi d'aucun nom de mthode, il reprsente alors un appel une mthode de mme nom P, la recherche de la mthode invoquer commence dans l'anctre immdiat de la classe de la mthode P actuelle et remonte la hirarchie.
procedure classeA.P(x,y : integer); begin Recherche et appel de inherited Q ( x ); Q ( x ) dans les anctres de classeA end;

procedure classeA.P(x,y : integer); begin <=> inherited P(x,y); inherited ; pui recherche et appel de P(x,y) dans les end; anctres de classeA

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

511

3. Polymorphisme de classes abstraites


Introduction
Les classes abstraites permettent de crer des classes gnriques expliquant certains comportements sans les implmenter et fournissant une implmentation commune de certains autres comportements pour l'hritage de classes. Les classes abstraites sont un outil prcieux pour le polymorphisme.

Vocabulaire et concepts :

Une classe abstraite est une classe qui ne peut pas tre instancie. Une classe abstraite peut contenir des mthodes dj implmentes. Une classe abstraite peut contenir des mthodes non implmentes. Une classe abstraite est hritable. On peut contsruire une hirarchie de classes abstraites. Pour pouvoir construire un objet partir d'une classe abstraite, il faut driver une classe non abstraite en une classe implmentant toutes les mthodes non implmentes.

Une mthode dclare dans une classe, non implmente dans cette classe, mais juste dfinie par la dclaration de sa signature, est dnomme mthode abstraite. Une mthode abstraite est une mthode liaison dynamique nayant pas dimplmentation dans la classe o elle est dclare. L' implmentation d'une mthode abstraite est dlgue une classe drive.

Si vous voulez utiliser la notion de classe abstraite pour fournir un comportement polymorphe un groupe de classes, elles doivent toutes hriter de la mme classe abstaite, comme dans l'exemple ci-dessous :

La classe Vhicule est abstraite, car la mthode Dmarrer est abstraite et sert de "modle" aux futures classes drivant de Vhicule, c'est dans les classes voiture, voilier et croiseur que l'on implmente le comportement prcis du genre de dmarrage. Notons au passage que dans la hirarchie prcdente, les classes vehicule Terrestre et Marin hritent de la classe Vhicule, mais n'implmentent pas la mthode abstraite Dmarrer, ce sont donc par construction des classes abstraites elles aussi.
Les bases de linformatique - programmation - ( rv. 04.01.2005 ) page

512

Les classes abstraites peuvent galement contenir des membres dj implments. Dans cette ventualit, une classe abstraite propose un certain nombre de fonctionnalits identiques pour tous ses futurs descendants (ceci n'est pas possible avec une interface).

Exemple : la classe abstraite Vhicule n'implmente pas la mthode abstraite Dmarrer, mais fournit et implante une mthode "RpartirPassagers" de rpartition des passagers bord du vhicule (fonction de la forme, du nombre de places, du personnel charg de s'occuper de faire fonctionner le vhicule...), elle fournit aussi et implante une mthode "PriodicitMaintenance" renvoyant la priodicit de la maintenance obligatoire du vhicule (fonction du nombre de km ou miles parcourus, du nombre d'heures d'activits,...)

Ce qui signifie que toutes les classes voiture, voilier et croiseur savent comment rpartir leurs ventuels passagers et quand effectuer une maintenance, chacune d'elle implmente son propre comportement de dmarrage.

Syntaxe de l'exemple en Delphi et en Java :


Delphi Vehicule = class public procedure Demarrer; virtual;abstract; procedure RpartirPassagers; virtual; procedure PriodicitMaintenance; virtual; end; Java abstract class ClasseA { public abstract void Demarrer( ); public void RpartirPassagers( ); public void PriodicitMaintenance( ); }

Utilisation pratique des classes abstraites


Utilisez une classe abstraite lorsque vous voulez :

regrouper un ensemble de mthodes prsentant des fonctionnalits identiques, dlguer l'implmentation de certaines mthodes une classe drive, disposer immdiatement de fonctionnalits concrtes pour d'autres mthodes, assurer un comportement polymorphe aux mthodes dont on dlgue l'implantation du code des classes drives.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

513

Exemple de code Delphi pour la hirarchie ci-dessous :

Soit en Delphi l'criture d'un exemple tir de cette hirarchie :


Delphi Unit UclassVehicules; interface Vehicule = class public procedure Demarrer; virtual;abstract; procedure RpartirPassagers; virtual; procedure PriodicitMaintenance; virtual; end; Terrestre = class ( Vehicule ) public procedure PriodicitMaintenance; override; end; Voiture = class ( Terrestre ) public procedure Demarrer; override; procedure RpartirPassagers; override; end; Marin = class ( Vehicule ) public procedure PriodicitMaintenance; override; end; Voilier = class ( Marin ) public procedure Demarrer; override; procedure RpartirPassagers; override; end; Croiseur = class ( Marin ) public procedure Demarrer; override; procedure RpartirPassagers; override; end; implementation //--- les mthodes implantes de la classe abstraite Vehicule : procedure Vehicule.RpartirPassagers; begin .......... end; procedure Vehicule.PriodicitMaintenance; begin

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

514

.......... end; //--- les mthodes implantes de la classe abstraite Terrestre : procedure Terrestre.PriodicitMaintenance; begin .......... end; //--- les mthodes implantes de la classe abstraite Marin : procedure Marin.PriodicitMaintenance; begin .......... end; //--- les mthodes implantes de la classe Voiture : procedure Voiture.Demarrer; begin .......... end; procedure Voiture.RpartirPassagers; begin .......... end; //--- les mthodes implantes de la classe Voilier : procedure Voilier.Demarrer; begin .......... end; procedure Voilier.RpartirPassagers; begin .......... end; //--- les mthodes implantes de la classe Croiseur : procedure Croiseur.Demarrer; begin .......... end; procedure Croiseur.RpartirPassagers; begin .......... end; end.

Dans cet exemple : Les classes Vehicule, Marin et Terrestre sont abstraites car aucune n'implmente la mthode abstraite Demarrer Les classes Marin et Terrestre contiennent chacune une surcharge dynamique implmente de la mthode virtuelle PriodicitMaintenance qui est dj implmente dans la classe Vhicule. Les classes Voiture, Voilier et Croiseur ne sont pas abstraites car elles implmentent les (la) mthodes abstraites de leurs parents.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

515

Exercice trait sur le polymorphisme


Objectifs : Comparer le polymorphisme et l'utilisation de tests de type if...then avec
l'oprateur is. On souhaite construire une application utilisant des classes de gestion de structures de donnes de noms (chanes). Ces classes devraient tre capables de lancer une intialisation de la structure, de trier par ordre croissant les donnes, de les afficher dans un diteur de texte. Nous voulons disposer d'une quatrime classe possdant une mthode gnrale d'dition d'une structure de donnes aprs son ordonnancement. Au dpart nous travaillons sur une classe contenant un tableau, une classe contenant une liste chane et une classe contenant un fichier. Chaque classe contient trois mthodes : Tri, Initialiser, et Ecrire qui ne seront qu'esquisses, car c'est la conception de la hirarchie qui nous intresse dans cet exemple et non le code interne. Le lecteur peut s'il le souhaite dvelopper un code personnel pour toutes ces mthodes.

LES TYPES DE STRUCTURES DE BASE PROPOSES


Nous proposons de travailler avec les types de donnes suivants : type
Element=record clef : integer; info : ShortString; end; fichier = file of Element; tableau=Array[1..100]of Element;

pointeur = ^chainon; chainon=record data:Element; suivant:pointeur end;

Nous supposons avoir fourni ces informations deux quipes de dveloppement leur laissant le choix de l'organisation des classes.

La premire quipe dcide d'implanter les 3 classes partir de la classe racine (TObject en Delphi). La seconde quipe de dveloppement a choisi pour le mme problme d'implmenter les 3 classes partir d'une hirarchie de classes fonde sur une classe abstraite.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

516

CLASSES DESCENDANT DE TObject


Equipe1-1) L'quipe implmente une gestion de structure de donnes partir de classe hritant toutes de la classe racine TObject avec des mthodes liaison statique.

Ttable=class T:Tableau; procedure Tri; procedure Initialiser; procedure Ecrire(Ed:Tedit); end ;

Tliste=class L:pointeur; procedure Tri; procedure Initialiser; procedure Ecrire(Ed:Tedit); end ;

Tfichier=class F:fichier; procedure Tri; procedure Initialiser; procedure Ecrire(Ed:Tedit); end ;

Ce choix permet aux membres de l'quipe n1 de dclarer et d'instancier des objets dans chaque classe : var S1:Ttable; S2:Tliste; S3:Tfichier;
S1:=Ttable.Create; S1.Initialiser; S1.Tri; S1.Ecrire(Form1.Edit1); S2:=Tliste.Create; S2.Initialiser; S2.Tri; S2.Ecrire(Form1.Edit1); S3:=Tfichier.Create; S3.Initialiser; S3.Tri; S3.Ecrire(Form1.Edit1);

L'quipe n1 pourra utiliser le polymorphisme d'objet en dclarant une refrence d'objet de classe racine puis en l'instanciant selon les besoins dans l'une des trois classes. Il sera alors ncessaire de transtyper la refrence en testant auparavant par scurit, l'appartenance de l'objet refrenc la bonne classe : var S1:TObject;
if S1 is Ttable then begin Ttable(S1).Initialiser; Ttable(S1).Tri; Ttable(S1).Ecrire(Form1.Edit1); End << S1:=Ttable.Create; >> if S1 is Tliste then if S1 is Tfichier then begin begin Tliste(S1).Initialiser; Tfichier(S1).Initialiser; Tliste(S1).Tri; Tfichier(S1).Tri; Tliste(S1).Ecrire(Form1.Edit1); Tfichier(S1).Ecrire(Form1.Edit1); end end << S1:=Tliste.Create; >> << S1:=TFichier.Create; >>

Dans l'application, l'quipe n1 construit une classe TUseData qui possde une mthode gnrale d'dition d'une structure de donnes aprs ordonnancement , cette mthode utilise le polymorphisme d'objet pour s'adapter la structure de donnes diter : TUseData=class Procedure Editer ( x : Tobject ); end ; C'est le paramtre formel de classe gnrale TObject qui est polymorphe, les valeurs effectives qu'il peut prendre sont : n'importe quel objet de classe hritant de Tobject.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

517

Code de la mthode Editer de TuseData : Procedure TUseData .Editer ( x : Tobject ); Begin if x is Ttable then begin Ttable(x).Tri; Ttable(x).Ecrire(Form1.Edit1); end Else if x is Tliste then begin Tliste(x).Tri; Tliste(x).Ecrire(Form1.Edit1); end Else if x is Tfichier then begin Tfichier(x)Tri; Tfichier(x).Ecrire(Form1.Edit1); end End;

Equipe1-2) L'quipe livre au client l'application contenant en de multiples endroits un appel la mthode Editer. Equipe1-3) Deux mois aprs la livraison et la mise en place, le client souhaite rajouter une nouvelle structure de donnes que nous nommons TDatas (par exemple de structure d'arbre binaire).
TAutre=class Data : TDatas; procedure Tri; procedure Initialiser; procedure Ecrire(Ed:Tedit); end ;

L'quipe propose de poursuivre la mme organisation en crant et en implantant une nouvelle classe drivant de TObject :

Equipe1-4) L'quipe 1 doit alors reprendre et modifier le code de la mthode Procedure Editer ( x : Tobject); de la classe TUseData, en y ajoutant le test du nouveau type TDatas comme suit :
Procedure TUseData .Editer ( x : Tobject); Begin if x is Ttable then else if x is Tliste then else if x is Tfichier then else if x is TDatas then begin TDatas (x).Tri; TDatas (x).Ecrire(Form1.Edit1); end;

End;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

518

Cette dmarche de rajout et de recompilation, les membres de l'quipe n1 devront l'accomplir dans chaque partie de l'application qui utilise la mthode Editer. Equipe1-5) L'quipe n1 envoie ensuite au client : La nouvelle classe et son code, ainsi que la nouvelle version de toutes les parties de l'application qui font appel la mthode Editer dont la prcdente version est maintenant caduque.

CLASSES DESCENDANT DE LA MEME CLASSE ABSTRAITE


Equipe2-1) L'quipe de dveloppement a choisi pour le mme problme d'implmenter une hirarchie de classes fonde sur une classe abstraite qui a t nomme TStructData.

TStructData=class procedure Tri;virtual;abstract; procedure Initialiser;virtual;abstract; procedure Ecrire(Ed:Tedit);virtual;abstract; end ;

Toutes les autres classes driveront de TStructData, et possderont des mthodes liaisons dynamiques afin d'utiliser ici le polymorphisme de mthodes :
Ttable=class (TStructData) T:Tableau; procedure Tri;override; procedure Initialiser;override; procedure Ecrire(Ed:Tedit);override; end ; Tliste=class (TStructData) L:pointeur; procedure Tri;override; procedure Initialiser;override; procedure Ecrire(Ed:Tedit);override; end ;

Tfichier=class (TStructData) F:fichier; procedure Tri;override; procedure Initialiser;override; procedure Ecrire(Ed:Tedit);override; end ;

Ce choix permet aux membres de l'quipe n2, comme pour ceux de l'quipe n1, de dclarer et d'instancier des objets dans chaque classe : var S1:Ttable; S2:Tliste; S3:Tfichier;
S1:=Ttable.Create; S1.Initialiser; S1.Tri; S1.Ecrire(Form1.Edit1); S2:=Tliste.Create; S2.Initialiser; S2.Tri; S2.Ecrire(Form1.Edit1); S3:=Tfichier.Create; S3.Initialiser; S3.Tri; S3.Ecrire(Form1.Edit1);

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

519

L'quipe n2 pourra utiliser le polymorphisme de mthode en dclarant une refrence d'objet de classe racine abstraite puis en l'instanciant selon les besoins dans l'une des trois classes. Mais ici, il ne sera pas ncessaire de transtyper la refrence ni de tester auparavant par scurit, l'appartenance de l'objet refrenc la bonne classe. En effet les mthodes Initialiser, Tri et Ecrire tant virtuelles, c'est le type de l'objet lors de l'excution qui dterminera le bon choix : Var S1 : TStrucData;

<< S1:=Ttable.Create; >> << S1:=Tliste.Create; >> << S1:=TFichier.Create; >> S1.Initialiser; S1.Tri; S1.Ecrire (Form1.Edit1);

Dans l'application, l'quipe n2 comme l'quipe n1, construit une classe TUseData qui possde une mthode gnrale d'dition d'une structure de donnes aprs ordonnancement, cette mthode utilise le polymorphisme d'objet et le polymorphisme de mthode pour s'adapter la structure de donnes diter : TUseData=class Procedure Editer ( x : TstructData ); end ;
Mthode Editer de TuseData : Mthode Editer de TuseData : quipe n2 Mthode Editer de TuseData : quipe n1 Procedure TUseData .Editer ( x : Tobject ); Begin if x is Ttable then begin Ttable(x).Tri; Ttable(x).Ecrire(Form1.Edit1); end else if x is Tliste then begin Tliste(x).Tri; Tliste(x).Ecrire(Form1.Edit1); end else if x is Tfichier then begin Tfichier(x)Tri; Tfichier(x).Ecrire(Form1.Edit1); end End;

Procedure TuseData.Editer ( x : TstructData ); Begin x.Tri; x.Ecrire(Form1.Edit1); End;

Equipe2-2) L'quipe livre au client l'application contenant en de multiples endroits un appel notre mthode Editer. Equipe2-3) Deux mois aprs l'quipe n2 s'est vu demander comme pour l'autre quipe,

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

520

de rajouter une nouvelle structure de donnes (par exemple de structure d'arbre binaire). L'quipe n2 cre et implante une nouvelle classe drivant de la classe abstraite TStructData comme pour les 3 autres classes dj existantes :

TAutre=class (TStructData) Data : TDatas; procedure Tri;override; procedure Initialiser;override; procedure Ecrire(Ed:Tedit);override; end ;

Grce au polymorphisme d'objet et de mthode liaison dynamique la mthode Editer fonctionne avec toutes les descendants de TstructData. Equipe2-4) L'quipe n2 n'a pas modifier le code de la mthode Procedure Editer ( x : TStructData). Equipe2-5) Il suffit l'quipe n2 d'envoyer au client la nouvelle classe et son code (toutes les parties de l'application qui font appel la mthode Editer fonctionneront correctement automatiquement) !

Squelettes des mthodes


Les deux quipes ont coopr entre elles, le code des mthodes est le mme quelque soit le choix effectu (hriter de TObject ou hriter d'une classe abstraite). //////////////////// Les tableaux ///////////////////////// procedure Ttable.Tri; begin //algorithme de tri d'un tableau T[1].info:=T[1].info+' : tableau tri' end; procedure Ttable.Initialiser; begin T[1].clef:=100; T[1].info:='Durand';//etc... end; procedure Ttable.Ecrire(Ed:Tedit); begin Ed.Text:='Clef= '+inttostr(T[1].clef)+'//'+T[1].info end; //////////////////// Les listes chanes ///////////////////////// procedure Tliste.Tri; begin //algorithme de tri d'une liste ... L.data.info:=L.data.info+' : liste trie' end; procedure Tliste.Initialiser; begin

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

521

new(L); L.data.clef:=100; L.data.info:='Durand'; L.suivant:=nil //etc... end; procedure Tliste.Ecrire(Ed:Tedit); begin Ed.Text:='Clef= '+inttostr(L.data.clef)+'//'+L.data.info end; //////////////////// Les fichiers ///////////////////////// procedure Tfichier.Tri; var UnElement:Element; begin //algorithme de tri d'un fichier ... AssignFile(F,'FichLocal'); reset(F); read(F,UnElement); CloseFile(F); UnElement.info:=UnElement.info+' : fichier tri'; reset(F); write(F,UnElement); CloseFile(F) end; procedure Tfichier.Initialiser; var UnElement:Element; begin AssignFile(F,'FichLocal'); rewrite(F); UnElement.clef:=100; UnElement.info:='Durand'; write(F,UnElement); //etc... CloseFile(F) end; procedure Tfichier.Ecrire(Ed:Tedit); var UnElement:Element; begin AssignFile(F,'FichLocal'); reset(F); read(F,UnElement); Ed.Text:='Clef= '+inttostr(UnElement.clef)+'//'+UnElement.info; CloseFile(F); end; end.

Conclusion
Le polymorphisme a montr dans cet exemple ses extraordinaires facults d'adaptation et de rutilisation. Nous avons constat le gain en effort de dveloppement obtenu par l'quipe qui a choisi de rflchir la construction d'une hirarchie fonde sur une classe abstraite. Nous conseillons donc de penser la notion de classe abstraite et aux mthodes virtuelles lors de la programmation d'un problme avec des classes.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

522

5.4 Programmation vnementielle et visuelle


Plan du chapitre:
Introduction Programmation visuelle base sur les pictogrammes Programmation oriente vnements Normalisation du graphe vnementiel le graphe vnementiel arcs et sommets les diagrammes d'tats UML rduits Tableau des actions vnementielles Interfaces lies un graphe vnementiel Avantages et modle de dveloppement RAD visuel le modle de la spirale (B.Boehm) le modle incrmental

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

523

1. Programmation visuelle base sur les pictogrammes


Le dveloppement visuel rapide d'application est fond sur le concept de programmation visuelle associe la monte en puissance de l'utilisation des Interactions Homme-Machine (IHM) dont le dynamisme rcent ne peut pas tre mconnu surtout par le dbutant. En informatique les systmes MacOs, Windows, les navigateurs Web, sont les principaux acteurs de l'ingnierie de l'IHM. Actuellement dans le dveloppement d'un logiciel, un temps trs important est consacr l'ergonomie et la communication, cette part ne pourra que grandir dans un avenir proche; car les utilisateurs veulent s'adresser des logiciels efficaces (ce qui va de soi) mais aussi conviviaux et faciles d'accs. Les dveloppeurs ont donc besoin d'avoir leur disposition des produits de dveloppement adapts aux ncessits du moment. A ce jour la programmation visuelle est une des rponses cette attente des dveloppeurs. La programmation visuelle au tout dbut a t conue pour des personnes n'tant pas des programmeurs en basant ses outils sur des manipulations de pictogrammes. Le raisonnement communment admis est qu'un dessin associ une action lmentaire est plus porteur de sens qu'une phrase de texte. A titre d'exemple ci-dessous l'on enlve le "fichier.bmp" afin de l'effacer selon deux modes de communication avec la machine: utilisation d'icnes ou entre d'une commande textuelle. Effacement avec un langage d'action visuelle (souris) Action : Rponse :

Effacement avec un langage textuel (clavier) Action : Rponse : del c:\Exemple\Fichier.bmp |? Nous remarquons donc dj que l'interface de communication MacOs, Windows dnomme "bureau lectronique" est en fait un outil de programmation de commandes systmes. Un langage de programmation visuelle permet "d'crire" la partie communication d'un programme uniquement avec des dessins, diagrammes, icnes etc... Nous nous intressons aux systmes RAD (Rapid Application Development) visuels, qui sont fonds sur des langages objets bases d'icnes ou pictogrammes. Visual Basic de MicroSoft est le premier RAD visuel a avoir t commercialis ds 1991, il est fond sur un langage Basic tendu incluant des objets tendus en VB.Net depuis 2001, puis ds 1995 Delphi le premier RAD visuel de Borland fond sur Pascal objet, puis actuellement toujours de Borland : C++Builder RAD visuel fond sur le langage C++ et Jbuilder, NetBeans RAD visuel de Sun fonds sur le langage Java, Visual C++, Visual J++ de Microsoft, Visual C# etc... Le dveloppeur trouve actuellement, une offre importante en outil de dveloppement de RAD visuel y compris en open source. Nous proposons de dfinir un langage de RAD visuel ainsi :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

524

Un langage visuel dans un RAD visuel est un gnrateur de code source du langage de base qui, derrire chaque action visuelle (dpt de contrle, click de souris, modifications des proprits, etc...) engendre des lignes de code automatiquement et d'un manire transparente au dveloppeur.

Des outils de dveloppement tels que Visual Basic ou Delphi sont adapts la programmation visuelle pour dbutant. Toutefois l'efficacit des dernires versions depuis 3 ans a tendu leur champ au dveloppement en gnral et dans l'activit industrielle et commerciale avec des versions "entreprise" pour VB et "Architect "pour Delphi. En outre, le systme windows est le plus largement rpandu sur les machines grand public (90% des PC vendus en sont quips), il est donc trs utile que le dbutant en programmation sache utiliser un produit de dveloppement (rapide si possible) sur ce systme. Proposition : Nous considrons dans cet ouvrage, la programmation visuelle la fois comme une fin et comme un moyen.

La programmation visuelle est sous-tendue par la ractivit des programmes en rponse aux actions de l'utilisateur. Il est donc ncessaire de construire des programmes qui rpondent des sollicitations externes ou internes et non plus de programmer squentiellement (ceci est essentiellement d aux architectures de Von Neumann des machines) : ces sollicitations sont appeles des vnements.

Le concept de programmation dirige ou oriente par les vnements est donc la composante essentielle de la programmation visuelle.

Terminons cette prsentation par 5 remarques sur le concept de RAD :


Utiliser un RAD simple mais puissant
Nous ne considrerons pas comme utile pour des dbutants de dmarrer la programmtion visuelle avec des RAD bass sur le langage C++. Du fait de sa large permissivit ce langage permet au programmeur d'adopter certaines attitudes dangereuses sans contrle possible. Seul le programmeur confirm au courant des piges et des subtilits de la programmation et du langage, pourra exploiter sans risque la richesse de ce type de RAD.

Avoir de bonnes mthodes ds le dbut


Le RAD Delphi de Borland conu en 1995 est une extension du langage Object Pascal, qui a des caractristiques trs proches de celles de C++ sans en avoir les inconvnients. L'aspect fortement typ du langage pascal autorise la prise en compte par le dveloppeur dbutant de bonnes attitudes de programmation.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

525

C'est Apple qui en a t le promoteur


Le premier environnement de dveloppement visuel professionnel bas sur Object Pascal a t conu par Apple pour le systme d'exploitation MacOs, sous la dnomination de MacApp en 1986. Cet environnement objet visuel permettait de dvelopper des applications MacIntosh avec souris, fentre, menus droulants etc...

Microsoft l'a popularis


Le RAD Visual Basic de MicroSof conu partir de 1992, bas sur le langage Basic avait pour objectif le dveloppement de petits logiciels sous Windows par des programmeurs non expriments et occasionnels. Actuellement il se dcline en VB.Net un langage totalement orient objet faisant partie intgrante de la plate-forme .Net Framework de Microsoft.

Le concept de RAD a de beaux jours devant lui


Le mtier de dveloppeur devrait terme, consister grce des outils tels que les RAD visuels, prendre un "caddie" et aller dans un supermarch de composants logiciels gnriques adapts son problme. Il ne lui resterait plus qu' assembler le flot des vnements reliant entre eux ces logiciels en kit.

2. Programmation oriente vnements


Sous les versions actuelles de Windows, systme multi-tches premptif sur micro-ordinateur, les concepts quant la programmation par vnement restent sensiblement les mmes que sous les anciennes versions.

Nous dirons que le systme dexploitation passe lessentiel de son " temps " attendre une action de lutilisateur (vnement). Cette action dclenche un message que le systme traite et envoie ventuellement une application donne.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

526

Une dfinition de la programmation oriente vnements Logique de conception selon laquelle un programme est construit avec des objets et leurs proprits et daprs laquelle les interventions de lutilisateur sur les objets du programme dclenchent lexcution des routines associes.

Par la suite, nous allons voir dans ce chapitre que la programmation dune application " windows-like " est essentiellement une programmation par vnements associe une programmation classique. Nous pourrons construire un logiciel qui ragira sur les interventions de lutilisateur si nous arrivons intercepter dans notre application les messages que le systme envoie. Or lenvironnement RAD ( Delphi , comme dailleurs avant lui Visual Basic de Microsoft), autorise la consultation de tels messages dun faon simple et souple. Deux approches pour construire un programme

Lapproche vnementielle intervient principalement dans linterface entre le logiciel et lutilisateur, mais aussi dans la liaison dynamique du logiciel avec le systme, et enfin dans la scurit. Lapproche visuelle nous aide et simplifie notre tche dans la construction du dialogue homme-machine. La combinaison de ces deux approches produit un logiciel habill et adapt au systme dexploitation.

Il est possible de relier certains objets entre eux par des relations vnementielles. Nous les reprsenterons par un graphe (structure classique utilise pour reprsenter des relations). Lorsque lon utilise un systme multi-fentr du genre windows, lon dispose du clavier et de la souris pour agir sur le systme. En utilisant un RAD visuel, il est possible de construire un logiciel qui se comporte comme le systme sur lequel il sexcute. Lintrt est que lutilisateur aura moins defforts accomplir pour se servir du programme puisquil aura des fonctionnalits semblables au systme. Le fait que lutilisateur reste dans un environnement familier au niveau de la manipulation et du confort du dialogue, assure le logiciel dun capital confiance de dpart non ngligeable.

3. Normalisation du graphe vnementiel


Il nexiste que peu dlments accessibles aux dbutants sur la programmation oriente objet par vnements. Nous construisons une dmarche mthodique pour le dbutant, en partant de remarques simples que nous dcrivons sous forme de schmas drivs des diagrammes d'tats d'UML. Ces schmas seront utiles pour nous aider dcrire et implanter des relations vnementielles en Delphi ou dans un autre RAD vnementiel.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

527

Voici deux principes qui pour linstant seront suffisants nos activits de programmation. Dans une interface windows-like nous savons que:

Certains vnements dclenchent immdiatement des actions comme par exemple des appels de routines systme. Dautres vnements ne dclenchent pas dactions apparentes mais activent ou dsactivent certains autres vnements systme.

Nous allons utiliser ces deux principes pour conduire notre programmation par vnements. Nous commencerons par le concept dactivation et de dsactivation, les autres vnements fonctionneront selon les mmes bases. Dans un enseignement sur la programmation vnementielle, nous avons constat que ce concept tait suffisant pour que les tudiants comprennent les fondamentaux de lapproche vnementielle. Remarque : Attention! Il ne sagit que dune manire particulire de conduire notre programmation, ce ne peut donc tre ni la seule, ni la meilleure (le sens accord au mot meilleur est relatif au domaine pdagogique). Cette dmarche sest rvle tre fructueuse lors denseignements dinitiation ce genre de programmation. Hypothses de construction Nous supposons donc que lorsque lutilisateur intervient sur le programme en cours dexcution, ce dernier ragira en premire analyse de deux manires possibles :

soit il lancera lappel dun routine (excution dune action, calcul, lecture de fichier, message un autre objet comme ouverture dune fiche etc...), soit il modifiera ltat dactivation dautres objets du programme et/ou de lui-mme, soit il ne se passera rien, nous dirons alors quil sagit dune modification nulle.

Ces hypothses sont largement suffisantes pour la plupart des logiciels que nous pouvons raisonnablement esprer construire en initiation. Les concepts plus techniques de messages dpassent assez vite ltudiant qui risque de replonger dans de " la grande bidouille ".

3.1 le graphe vnementiel arcs et sommets


Nous proposons de construire un graphe dans lequel :

chaque sommet est un objet sensible un vnement donn.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

528

Lvnement donn est dclench par une action extrieure lobjet.

Les arcs du graphe reprsentent des actions lances par un sommet. Les actions sont de 4 types

Soit le graphe vnementiel suivant compos de 5 objets sensibles chacun un vnement particulier dnot Evt-1,..., Evt-5; ce graphe comporte des ractions de chaque objet l'vnement auquel il est sensible :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

529

Imaginons que ce graphe corresponde une analyse de chargements de deux types diffrents de donnes des fins de calcul sur leurs valeurs.
La figure suivante propose un tel graphe vnementiel partir du graphe vide prcdent.

Cette notation de graphe vnementiel est destine s'initier la pratique de la description d'au maximum 4 types de ractions d'un objet sur la sollicitation d'un seul vnement. Remarques :
L'arc nomm, reprsentant l'activation d'une mthode correspond trs exactement la notation UML de l'envoi d'un message. Lorsque nous voudrons reprsenter d'une manire plus complte d'autres ractions d'un seul objet plusieurs vnements diffrents, nous pourrons utiliser la notation UML rduite de diagramme d'tat pour un objet (rduite parce qu'un objet visuel ne prendra pour nous, que 2 tats: activ ou dsactiv).

3.2 les diagrammes d'tats UML rduits Nous livrons ci-dessous la notation gnrale de diagramme d'tat en UML, les cas particuliers et les dtails complets sont dcrits dans le document de spcification d'UML.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

530

Voici les diagrammes d'tats rduits extraits du graphe vnementiel prcdent, pour les objets Evt-1 et Evt-2 :

.....

etc...

Nous remarquerons que cette criture, pour l'instant, ne produit pas plus de sens que le graphe prcdent qui comporte en sus la vision globale des interrelations entre les objets. Ces diagrammes d'tats rduits deviennent plus intressants lorsque nous voulons exprimer le fait par exemple, qu'un seul objet Obj1 ragit 3 vnements (vnement-1, vnement-2, vnement-3). Dans ce cas dcrivons les portions de graphe vnementiel associs chacun des vnements : Raction de obj1 l'vnement-1 : Raction de obj1 l'vnement-2 :

Raction de obj1 l'vnement-3 :

Synthtisons dans un diagramme d'tat rduit les ractions ces 3 vnements :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

531

Lorsque nous jugerons ncessaire la comprhension de relations vnementielles dans un logiciel visuel, nous pourrons donc utiliser ce genre de diagramme pour renforcer la smantique de conception des objets visuels. La notation UML sur les diagrammes d'tats comprend les notions d'tat de dpart, de sortie, imbriqu, historis, concurrents... Lorsque cela sera ncessaire nous utiliserons la notation UML de synchronisation d'vnements :

ev1 Dans le premier cas la notation reprsente la conjonction des deux vnements ev1 et ev2 qui dclenche l'vnement ev3. ev3 ev4 Dans le second cas la notation reprsente l'vnement ev4 dclenchant conjointement les deux vnements ev5 et ev6. ev5

ev2

ev6

4. Tableau des actions vnementielles


Lexemple de graphe vnementiel prcdent correspond une application qui serait sensible 5 vnements nots EVT-1 EVT-5, et qui excuterait 3 procdures utilisateur. Nous

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

532

notons dans un tableau (nomm " tableau des actions vnementielles ")les rsultats obtenus par analyse du graphe prcdent, vnement par vnement.. EVT-1 EVT-2 EVT-3 activable
EVT-4 activable

EVT-3

EVT-4 EVT-5

Appel de procdure utilisateur "chargement-1" dsactivation de l vnement EVT-2 Appel de procdure utilisateur "Analyser" EVT-2 activable EVT-2 dsactiv EVT-5 activable EVT-4 dsactiv immdiatement Appel de procdure utilisateur "chargement-2"

Nous adjoignons ce tableau une table des tats des vnements ds le lancement du logiciel (elle correspond ltat initial des objets). Par exemple ici : Evt1 Evt2 Evt3 Evt4 Evt5 etc... activ dsactiv activ activ dsactiv

5. Interfaces lies un graphe vnementiel


construction dinterfaces lies au graphe prcdent
Interface n1

Dans lexemple de droite, (i1,i2,i3,i4,i5)est une permutation sur (1,2,3,4,5) .

Ce qui nous donne dj 5!=120 interfaces possibles avec ces objets et uniquement avec cette topologie.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

533

La figure prcdente montre une IHM (construite avec des objets Delphi) partir du graphe vnementiel tudi plus haut. Ci-dessous deux autres structures dinterfaces possibles avec les mmes objets combins diffremment et associs au mme graphe vnementiel :

Interface n2

Interface n3

Pour les choix n2 et n3, il y a aussi 120 interfaces possibles

6. Avantages du modle de dveloppement RAD visuel


Lapproche uniquement structure (privilgiant les fonctions du logiciel) impose dcrire du code long et compliqu en risquant de ne pas aboutir, car il faut tout tester afin dassurer un bon fonctionnement de tous les lments du logiciel. Lapproche vnementielle prfre btir un logiciel fond sur une construction graduelle en fonction des besoins de communication entre lhumain et la machine. Dans cette optique, le programmeur labore les fonctions associes une action de communication en privilgiant le dialogue. Ainsi les actions internes du logiciel sont subordonnes au flux du dialogue.

Avantages lis la programmation par RAD visuel

Il est possible de construire trs rapidement un prototype. Les fonctionnalits de communication sont les guides principaux du dveloppement (approche plus vivante et attrayante). Ltudiant est impliqu immdiatement dans le processus de conception - construction.

Ltudiant acquiert trs vite comme naturelle lattitude de rutilisation en se servant de " logiciels en kit " (soit au dbut des composants visuels ou non, puis par la suite ses propres composants).

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

534

Il ny a pas de conflit ni dincohrence avec la dmarche structure : les algorithmes tant conus comme des botes noires permettant dimplanter certaines actions, seront rutiliss immdiatement. La mthodologie objet de COO et de POO reste un facteur dintgration gnral des activits du programmeur. Les actions de communications classiques sont assures immdiatement par des objets standards (composants visuels ou non) ragissant des vnements extrieurs. Le RAD fournira des classes dobjets standards non visuels (extensibles si ltudiant augmente sa comptence) grant les structures de donnes classiques (Liste, arbre, etc..). Lextensibilit permet lenseignant de rajouter ses kits personnels dobjets et de les mettre la disposition des tudiants comme des outils standards.

Modles de dveloppement avec un RAD visuel objet


Le dveloppement avec ce genre de produit autorise une logique gnrale articule sur la combinaison de deux modles de dveloppement :

le modle de la spirale (B.Boehm) en version simplifie

Dans le modle de la spirale la programmation exploratoire est utilise sous forme de prototypes simplifis cycle aprs cycle. L'analyse s'amliore au cours de chaque cycle et fixe le type de dveloppement pour ce tour de spirale.

le modle incrmental Il permet de raliser chaque prototype avec un bloc central au dpart, s'enrichissant chaque phase de nouveaux composants et ainsi que de leurs interactions.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

535

Associ un cycle de prototypage dans la spirale, une seule famille de composants est dveloppe pour un cycle fix.

prototype 1 :

prototype 2 :

prototype 3 :

etc...

Ce modle de dveloppement l'aide d'objets visuels ou non, fournira en fin de parcours un prototype oprationnel qui pourra s'intgrer dans un projet plus gnral. Nous verrons sur des exemples comment ce type d'outil peut procurer aussi des avantages au niveau de la programmation dfensive.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

536

5.5 Les vnements avec Delphi


Plan du chapitre:

Programmes vnementiels
Pointeur de mthode Affecter un pointeur de mthode Un vnement est un pointeur de mthode Quel est le code engendr Exercice-rcapitulatif Notice mthodologique pour crer un nouvel vnement

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

537

1. Programmes vnementiels avec Delphi


Delphi comme les autres RAD vnementiels permet de construire du code qui est excut en rponse des vnements. Un vnement Delphi est une proprit d'un type spcial que nous allons examiner plus loin. Le code de raction un vnement particulier est une mthode qui s'appelle un gestionnaire de cet vnement. Un vnement est en fait un pointeur vers la mthode qui est charge de le grer. Dfinissons la notion de pointeur de mthode qui est utilise ici, notion largement utilise en gnral dans les langages objets.

Pointeur de mthode
Un pointeur de mthode est une paire de pointeurs (adresses mmoire), le premier contient l'adresse d'une mthode et le second une rfrence l'objet auquel appartient la mthode.

Schma ci-aprs d'un objet Obj1 de classe clA contenant un champ du type pointeur vers la mthode meth1 de l'objet Obj2 de classe clB :

Pointeur de mthode en Delphi


Pour pointer la mthode d'une instance d'objet en Delphi, nous devons dclarer un nouveau type auquel nous ajoutons la fin le qualificateur of object .

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

538

Exemples de types pointeurs de mthode et de variable de type pointeur de mthode :


type ptrMethode1 = procedure of object; ptrMethode2 = procedure (x : real) of object; ptrMethode3 = procedure (x,y: integer; var z:char) of object; var Proc1 : ptrMethode1; // pointeur vers une mthode sans paramtre Proc2 : ptrMethode2; // pointeur vers une mthode un paramtre real Proc3 : ptrMethode3; // pointeur vers une mthode trois paramtres 2 entiers, 1 char

Schma ci-aprs d'un objet Obj1 de classe clA contenant un champ proc1 du type ptrMethode1 qui pointe vers la meth1 de l'objet Obj2 de classe clB. On suppose que l'adresse mmoire de l'objet est 14785 et l'adresse de la mthode meth1 de l'objet est 14792 :

Il est impratif que la mthode vers laquelle pointe la variable de pointeur de mthode soit du type prvu par le type pointeur de mthode, ici la mthode meth1 doit obligatoirement tre une procdure sans paramtre (compatibilit d'en-tte). Schma ci-aprs d'un objet Obj1 de classe clA contenant un champ proc2 du type ptrMethode2 qui pointe vers la meth2 de l'objet Obj2 de classe clB. On suppose que l'adresse mmoire de l'objet est 14785 et l'adresse de la mthode meth2 de l'objet est 14805 :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

539

La remarque prcdente sur l'obligation de compatibilit de l'en-tte de la mthode et le type pointeur de mthode implique que la mthode meth2 doit ncessairement tre une procdure un seul paramtre real.

Affecter un pointeur de mthode


Nous venons de voir comment dclarer un type pointeur de mthode et un champ de ce mme type, nous avons signal que ce champ doit pointer vers une mthode ayant une en-tte compatible avec le type pointeur de mthode, il nous reste connatre le mcanisme qu'utilise Delphi pour lier un champ pointeur et une mthode pointer.
Types pointeurs de mthodes ptrMethode1 = procedure of object; ptrMethode2 = procedure (x : real) of object; champs de pointeurs de mthodes Proc1 : ptrMethode1; // pointeur vers une mthode sans paramtre Proc2 : ptrMethode2; // pointeur vers une mthode un paramtre real

Diverses mthodes : procedure P1; begin end;

procedure P2 (x:real); begin end;

procedure P3 (x:char); begin end;

procedure P4; begin end;

Recensons d'abord les compatibilits d'en-tte qui autoriseront le pointage de la mthode : Proc1 peut pointer vers P1 , P4 qui sont les deux seules mthodes compatibles. Proc2 ne peut pointer que vers P2 qui est la seule mthode un paramtre de type real. La liaison (le pointage) s'effectue tout naturellement travers une affectation : L'affectation Proc1 := P1; indique que Proc1 pointe maintenant vers la mthode P1 et peut tre utilis comme un identificateur de procdure ayant la mme signature que P1. Exemple d'utilisation : Proc2 := P2; // liaison du pointeur et de la procdure P2 Proc2(45.8); // appel de la procdure vers laquelle Proc2 pointe avec passage du paramtre 45.8

Un vnement est un pointeur de mthode


Nous avons indiqu que les gestionnaires d'vnements sont des mthodes, les champs du genre vnements prsents dans les classes Delphi sont en fait des pointeurs de mthode, qui peuvent pointer vers des gestionnaires d'vnements.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

540

Un type d'vnement est donc un type pointeur de mthode, Delphi possde plusieurs types d'vnements par exemple :
TNotifyEvent = procedure (Sender: TObject) of object; TMouseMoveEvent = procedure (Sender: TObject; Shift: TShiftState; X, Y: Integer) of object; TKeyPressEvent = procedure (Sender: TObject; var Key: Char) of object;

etc Un vnement est donc une proprit de type pointeur de mthode (type vnement) :
property OnClick: TNotifyEvent; // vnement click de souris property OnMouseMove: TMouseMoveEvent; // vnement passage de la souris property OnKeyPress: TKeyPressEvent; // vnement touche de clavier presse

Quel est le code engendr pour grer un vnement ?


Intressons nous maintenant au code engendr par un programme simple constitu d'une fiche Form1 de classe TForm1 avec un objet Button1 de classe Tbutton dpos sur la fiche :

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; private { Dclarations prives } public { Dclarations publiques } end; var Form1: TForm1; implementation {$R *.dfm} end.

object Form1: TForm1 Left = 198 Le code intermdiaire cach Top = 109 au programmeur. Il permet Width = 245 l'initialisation automatique Height = 130 de la fiche et de ses Caption = 'Form1' composants. Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [ ] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Button1: TButton Left = 80 Top = 32 Width = 75 Height = 25 Caption = 'Button1' TabOrder = 0 end end Le code intermdiaire cach de l'objet Button1 dpos sur la fiche Form1.

Le code source apparent fournit au programmeur. Il permet l'intervention du programmeur sur la fiche et sur ses composants.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

541

Demandons Delphi de nous fournir ( partir de l'inspecteur d'objet) les gestionnaires des 3 vnements OnClick, OnMouseMove et OnKeyPress de raction de l'objet Button1 au click de souris, au passage de la souris et l'appui sur une touche du clavier:

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type TForm1 = class(TForm) Button1: TButton; procedure Button1Click (Sender: TObject); procedure Button1MouseMove (Sender: TObject; Shift: TShiftState; X,Y: Integer); procedure Button1KeyPress (Sender: TObject; var Key: Char); private { Dclarations prives } public { Dclarations publiques } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click (Sender: TObject); begin { Gestionnaire OnClick } end;

Nouveau code intermdiaire cach de l'objet Button1 contenant les affectations des vnments leurs gestionnaires.

object Button1: TButton Left = 80 Top = 32 Width = 75 Height = 25 Caption = 'Button1' TabOrder = 0 OnClick = Button1Click OnKeyPress = Button1KeyPress OnMouseMove = Button1MouseMove end

procedure TForm1.Button1MouseMove (Sender: TObject; Shift: TShiftState; X,Y: Integer); begin { Gestionnaire OnMouseMove } end; procedure TForm1.Button1KeyPress (Sender: TObject; var Key: Char); begin { Gestionnaire OnKeyPress } end; end.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

542

Delphi engendre un code source visible en pascal objet modifiable et un code intermdiaire (que l'on peut voir et ventuellement modifier) :

Le code source visible est celui qui nous sert programmer nos algorithmes, nos classes, et les ractions aux vnements. Le code intermdiaire est gnr au fur et mesure que nous intervenons visuellement sur l'interface et contient l'initialisation de l'interface (affectations de gestionnaires d'vnements, couleurs des fonds, positions des composants, taille, polices de caractres, conteneurs et contenus etc) il sert au compilateur.

Nous venons de voir que Delphi a gnr en code intermdiaire pour nous, les affectations de chaque vnement un gestionnaire :
OnClick = Button1Click OnKeyPress = Button1KeyPress OnMouseMove = Button1MouseMove

Et il nous a fournit les squelettes vides de chacun des trois gestionnaires :


procedure TForm1.Button1Click (Sender: TObject); procedure TForm1.Button1MouseMove (Sender: TObject; Shift: TShiftState; X,Y: Integer); procedure TForm1.Button1KeyPress (Sender: TObject; var Key: Char);

La dernire tape du processus de programmation de la raction du Button1 est de programmer du code l'intrieur des squelettes des gestionnaires. Lors de l'excution si nous cliquons avec la souris sur le Button1, un mcanisme d'interception et de rpartition figur ci-dessous appelle le gestionnaire de l'vnment OnClick dont le corps a t programm :

fig : Appel du gestionnaire procedure TForm1.Button1Click (Sender: TObject) sur click de souris

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

543

Exercice-rcapitulatif
Nous voulons construire une interface permettant la saisie par lutilisateur de deux entiers et lautorisant effectuer leur somme et leur produit uniquement lorsque les entiers sont entrs tous les deux. Aucune scurit nest apporte pour linstant sur les donnes.

Voici l'tat visuel de l'interface au lancement du programme :

2 zones de saisie 2 boutons d'actions 2 zones d'affichages des rsultats

Ds que les deux entiers sont entrs, le bouton Calcul est activ:

Lorsque lon clique sur le bouton Calcul, le bouton EFFACER est activ et les rsultats s'affichent dans leurs zones respectives :

Un clic sur le bouton EFFACER ramne linterface ltat initial.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

544

Graphe vnementiel complet de l'interface

Avec comme conventions sur les messages : X1 = excuter les calculs sur les valeurs entres. X2 = excuter leffacement des rsultats. M1 = message ledit1 de tout effacer. M2 = message ledit2 de tout effacer.

Table des actions vnementielles associes au graphe


Changer Edit1 Changer EDIT2 Clic CALCUL Clic EFFACER Calcul activable (si changer Edit2 a eu lieu) Calcul activable (si changer Edit1 a eu lieu) Excuter X1 EFFACER activable Afficher les rsultats EFFACER dsactiv CALCUL dsactiv Message M1 Message M2

Table des tats initiaux des objets sensibles aux vnements


Edit1 Edit2 Buttoncalcul Buttoneffacer activ activ dsactiv dsactiv

Nous voulons disposer dun bouton permettant de lancer le calcul lorsque cest possible et dun bouton permettant de tout effacer. Les deux boutons seront dsactivs au dpart. Nous choisissons 6 objets visuels : deux TEdit, Edit1 et Edit2 pour la saisie ; deux Tbutton, ButtonCalcul et Buttoneffacer pour les changements de plans daction ; deux Tlabel LabelSomme et LabelProduit pour les rsultats

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

545

Les objets visuels Delphi choisis


Edit1: TEdit; Edit2: TEdit; LabelSomme: TLabel; LabelProduit: TLabel; ButtonCalcul: TButton;

Buttoneffacer: TButton;

Construction progressive du gestionnaire d'vnement Onchange


Nous devons raliser une synchronisation des entres dans Edit1 et Edit2 : le dverrouillage (activation) du bouton " ButtonCalcul " ne doit avoir lieu que lorsque Edit1 et Edit2 contiennent des valeurs. Ces deux objets de classe TEdit, sont sensibles lvnement OnChange qui indique que le contenu du champ text a t modifi, laction est indique dans le graphe vnementiel sous le vocable " changer ". La synchronisation se fera laide de deux drapeaux binaires (des boolens) qui seront levs chacun sparment par les TEdit lors du changement de leur contenu. Le drapeau Som_ok est lev par lEdit1, le drapeau Prod_ok est lev par lEdit2.
Implantation : deux champs privs boolens

Som_ok , Prod_ok : boolean; Le drapeau Som_ok est lev par lEdit1 lors du changement du contenu de son champ text, sur lapparition de lvnement OnChange, il en est de mme pour le drapeau Prod_ok et lEdit2 :
Implantation n1 du gestionnaire de OnChange : procedure TForm1.Edit1Change(Sender: TObject); begin Som_ok:=true; // drapeau de Edit1 lev end; procedure TForm1.Edit2Change(Sender: TObject); begin Prod_ok:=true; // drapeau de Edit2 lev end;

Une mthode prive de test vrifiera que les deux drapeaux ont t levs et lancera lactivation du ButtonCalcul.
procedure TForm1.TestEntrees; {les drapeaux sont-ils levs tous les deux ?} begin if Prod_ok and Som_ok then ButtonCalcul.Enabled:=true // si oui: le bouton calcul est activ end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

546

Nous devons maintenant tester lorsque nous levons un drapeau si lautre nest pas dj lev. Cette opration seffectue dans les gestionnaires de lvnement OnChange de chacun des Edit1 et Edit2 :
Implantation n2 du gestionnaire de OnChange : procedure TForm1.Edit1Change(Sender: TObject); begin Som_ok:=true; // drapeau de Edit1 lev TestEntrees; end; procedure TForm1.Edit2Change(Sender: TObject); begin Prod_ok:=true; // drapeau de Edit2 lev TestEntrees; end;

Construction des gestionnaires d'vnement Onclick


Nous devons grer lvnement clic sur le bouton calcul qui doit calculer la somme et le produit, placer les rsultats dans les deux Tlabels et activer le Buttoneffacer.
Implantation du gestionnaire de OnClick du ButtonCalcul : procedure TForm1.ButtonCalculClick(Sender: TObject); var S , P : integer; begin S:=strtoint(Edit1.text); // transtypage : string integer P:=strtoint(Edit2.text); // transtypage : string integer LabelSomme.caption:=inttostr(P+S); LabelProduit.caption:=inttostr(P*S); Buttoneffacer.Enabled:=true // le bouton effacer est activ end;

Nous codons une mthode prive dont le rle est de rinitialiser linterface son tat de dpart indiqu dans la table des tats initiaux : Edit1 Edit2 Buttoncalcul Buttoneffacer Activ Activ Dsactiv dsactiv
procedure TForm1.RAZTout; begin Buttoneffacer.Enabled:=false; //le bouton effacer se dsactive ButtonCalcul.Enabled:=false; //le bouton calcul se dsactive LabelSomme.caption:='0'; // RAZ valeur somme affiche LabelProduit.caption:='0'; // RAZ valeur produit affiche Edit1.clear; // message M1 Edit2.clear; // message M2 Prod_ok:=false; // RAZ drapeau Edit2 Som_ok:=false; // RAZ drapeau Edit1 end;

Nous devons grer lvnement click sur le Buttoneffacer qui doit remettre linterface son tat initial (par appel la procdure RAZTout ) :
Implantation du gestionnaire de OnClick du Buttoneffacer: procedure TForm1.ButtoneffacerClick(Sender: TObject); begin RAZTout; end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

547

Au final, lorsque l'application se lance et que l'interface est cre nous devons positionner tous les objets ltat initial (nous choisissons de lancer cette initialisation sur lvnement OnCreate de cration de la fiche):
Implantation du gestionnaire de OnCreate de la fiche Form1: procedure TForm1.FormCreate(Sender: TObject); begin RAZTout; end;

Si nous essayons notre interface nous constatons que nous avons un problme de scurit deux niveaux dans notre saisie :

Le premier niveau est celui des corrections apportes par lutilisateur (effacement de chiffres dj entrs) et la synchronisation avec lventuelle vacuit dau moins un des champs text aprs une telle modification : en effet lutilisateur peut effacer tout le contenu dun " Edit " et lancer alors le calcul, provoquant ainsi des erreurs. Le deuxime niveau classique est celui du transtypage incorrect, dans le cas o lutilisateur commet des fautes de frappe et rentre des donnes autres que des chiffres (des lettres ou dautres caractres du clavier).

Amliorations de scurit du premier niveau par plan daction


Nous protgeons les calculs dans le logiciel, par un test sur la vacuit du champ text de chaque objet de saisie TEdit. Dans le cas favorable o le champ nest pas vide, on autorise la saisie ; dans lautre cas on dsactive systmatiquement le ButtonCalcul et lon abaisse le drapeau qui avait t lev lors de lentre du premier chiffre, ce qui empchera toute erreur ultrieure. Lutilisateur comprendra de lui-mme que tant quil ny a pas de valeur dans les entres, le logiciel ne fera rien et on ne passera donc pas au plan daction suivant (calcul et affichage). Cette amlioration seffectue dans les gestionnaires dvnement OnChange des deux TEdit.
Implantation n2 du gestionnaire de OnChange : procedure TForm1.Edit1Change(Sender: TObject); begin if Edit1.text<' ' then // champ text non vide ok ! begin Som_ok:=true; TestEntrees; end else begin ButtonCalcul.enabled:=false; // bouton dsactiv Som_ok:=false; // drapeau de Edit1 baiss end end; procedure TForm1.Edit1Change(Sender: TObject); begin if Edit2.text<' ' then // champ text non vide ok ! begin Prod_ok:=true; TestEntrees; end else begin ButtonCalcul.enabled:=false; //bouton dsactiv Prod_ok:=false; // drapeau de Edit2 baiss end end;

On remarque que les deux codes prcdents sont trs proches, ils diffrent par leTEdit et le drapeau auxquels ils s'appliquent. Il est possible de rduire le code redondant en construisant par exemple une mthode prive avec deux paramtres.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

548

Regroupement du code
Soit la mthode prive Autorise possdant deux paramtres, le premier est la rfrence d'un des deux TEdit, le second le drapeau boolen associ :
procedure TForm1.Autorise ( Ed : TEdit ; var flag : boolean ); begin if Ed.text<' ' then // champ text non vide ok ! begin flag :=true; TestEntrees; end else begin ButtonCalcul.enabled:=false; //bouton dsactiv flag:=false; // drapeau de Ed baiss end end; Nouvelle implantation n2 du gestionnaire de OnChange : procedure TForm1.Edit1Change(Sender: TObject); procedure TForm1.Edit2Change(Sender: TObject); begin begin Autorise ( Edit1 , Som_ok ); Autorise ( Edit2 , Prod_ok ); end; end;

Code final o tout est regroup dans la classe TForm1


unit UFcalcul; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1= class ( TForm ) Edit1: TEdit; Edit2: TEdit; ButtonCalcul: TButton; LabelSomme: TLabel; LabelProduit: TLabel; Buttoneffacer: TButton; procedure FormCreate(Sender: TObject); procedure Edit1Change(Sender: TObject); procedure Edit2Change(Sender: TObject); procedure ButtonCalculClick(Sender: TObject); procedure ButtoneffacerClick(Sender: TObject); private { Dclarations prives } Som_ok , Prod_ok : procedure TestEntrees; procedure RAZTout; procedure Autorise ( Ed : TEdit ; var flag : boolean ); public { Dclarations publiques } end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

549

implementation { --------------- Mthodes prives ---------------------} procedure TForm1.TestEntrees; {les drapeaux sont-ils levs tous les deux ?} begin if Prod_ok and Som_ok then ButtonCalcul.Enabled:=true // si oui: le bouton calcul est activ end; procedure TForm1.RAZTout; begin Buttoneffacer.Enabled:=false; //le bouton effacer se dsactive ButtonCalcul.Enabled:=false; //le bouton calcul se dsactive LabelSomme.caption:='0'; // RAZ valeur somme affiche LabelProduit.caption:='0'; // RAZ valeur produit affiche Edit1.clear; // message M1 Edit2.clear; // message M2 Prod_ok:=false; // RAZ drapeau Edit2 Som_ok:=false; // RAZ drapeau Edit1 end; procedure TForm1.Autorise ( Ed : TEdit ; var flag : boolean ); begin if Ed.text<' ' then // champ text non vide ok ! begin flag :=true; TestEntrees; end else begin ButtonCalcul.enabled:=false; //bouton dsactiv flag:=false; // drapeau de Ed baiss end end; { ------------------- Gestionnaires d'vnements -------------------} procedure TForm1.FormCreate(Sender: TObject); begin RAZTout; end; procedure TForm1.Edit1Change(Sender: TObject); begin Autorise ( Edit1 , Som_ok ); end; procedure TForm1.Edit2Change(Sender: TObject); begin Autorise ( Edit2 , Prod_ok ); end; procedure TForm1.ButtonCalculClick(Sender: TObject); var S , P : integer; begin S:=strtoint(Edit1.text); // transtypage : string integer P:=strtoint(Edit2.text); // transtypage : string integer LabelSomme.caption:=inttostr(P+S); LabelProduit.caption:=inttostr(P*S); Buttoneffacer.Enabled:=true // le bouton effacer est activ end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

550

procedure TForm1.ButtoneffacerClick(Sender: TObject); begin RAZTout; end; end.

Un gestionnaire d'vnement centralis grce au : - polymorphisme d'objet - pointeur de mthode


Chaque Edit possde son propre gestionnaire de l'vnement OnChange :

procedure TForm1.Edit1Change(Sender: TObject); begin Autorise ( Edit1 , Som_ok ); end;

procedure TForm1.Edit2Change(Sender: TObject); begin Autorise ( Edit2 , Prod_ok ); end;

On peut avoir envie de mettre en place un gestionnaire unique de l'vnement OnChange, puis de le lier chaque zone de saisie Edit1 et Edit2 (souvenons-nous qu'un champ d'vnement est un pointeur de mthode) :

Nous dfinissons d'abord une mthode public par exemple, qui jouera le rle de gestionnaire centralis d'vnement, nous la nommons TexteChange.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

551

Cette mthode pour tre considre comme un gestionnaire de l'vnement OnChange, doit obligatoirement tre compatible avec le type de l'vnement Onchange. Une consultation de la documentation Delphi nous indique que :
property OnChange: TNotifyEvent;

L'vnement OnChange est du mme type que l'vnement OnClick ( TnotifyEvent = procedure(Sender:Tobject) of object ), donc notre gestionnaire centralis TexteChange doit avoir l'en-tte suivante : procedure TexteChange ( Sender : Tobject ); Le paramtre Sender est la rfrence de l'objet qui appelle la mthode qui est pass automatiquement lors de l'excution, en l'occurrence ici lorsque Edit1 appellera ce gestionnaire c'est la rfrence de Edit1 qui sera passe comme paramtre, de mme lorsqu'il s'agira d'un appel de Edit2.
Implantation du gestionnaire centralis procedure TForm1.TexteChange(Sender: TObject); begin if Sender is TEdit then begin if (Sender as TEdit )=Edit1 then Autorise ( (Sender as TEdit ) , Som_ok ); else Autorise ( (Sender as TEdit ) , Prod_ok ); end end;

On teste si l'metteur Sender est bien un TEdit,

polymorphisme d'objet :
Si l'metteur est Edit1 on le transtype en TEdit pour pouvoir le passer en premier paramtre la mthode Autorise sinon c'est Edit2 et l'on fait la mme opration.

On lie maintenant ce gestionnaire chacun des champs OnChange de chaque TEdit ds la cration de la fiche :
procedure TForm1.FormCreate(Sender: TObject); begin RAZTout; Edit1.OnChange := TexteChange ; Edit2.OnChange := TexteChange ; end;

pointeur de mthode
chaque champ Onchange pointe vers le mme gestionnaire (mthode)

TForm1= class ( TForm ) Edit1: TEdit; procedure FormCreate(Sender: TObject); procedure ButtonCalculClick(Sender: TObject); procedure ButtoneffacerClick(Sender: TObject); private { Dclarations prives } Som_ok , Prod_ok : procedure TestEntrees; procedure RAZTout; procedure Autorise ( Ed : TEdit ; var flag : boolean ); public { Dclarations publiques } procedure TexteChange(Sender: TObject); end;

Le gestionnaire centralis est dclar ici, puis il est implment la section implementation de la unit.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

552

NOTICE METHODOLOGIQUE
construire un nouvel vnement Objectif : Nous proposons ici en suivant pas pas l'enrichissement du code de
montrer comment implanter un nouvel vnement nomm OnTruc dans une classe dnote ClassA. Puis nous appliquerons cette dmarche une pile Lifo qui sera rendu sensible l'empilement et au dpilement, par adjonction de deux vnements la classe.

Pour construire un nouvel vnement dans ClassA :


Il nous faut d'abord dfinir un type pour l'vnement : EventTruc Il faut ensuite mettre dans ClassA une proprit d'vnement : property OnTruc : EventTruc Il faut crer un champ priv nomm FOnTruc de type EventTruc en lecture et criture qui servira de champ de stockage de la proprit OnTruc.

Version-1 du code source


Unit UDesignEvent ; interface type EventTruc = procedure (Sender:TObject; info:string) of object ; ClassA = class private

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

553

FOnTruc : EventTruc ; public OnTruc : EventTruc read FOnTruc write FOnTruc ; end; implementation

end.

Il nous faut maintenant construire une mthode qui va dclencher l'vnement, nous utilisons une procdure surchargeable dynamiquement afin de permettre des redfinitions utlrieures par les descendants.

Lorsque l'vnement se nomme OnXXX, les quipes de dveloppement Borland donnent la fin du nom de l'vnement OnXXX la procdure redfinissable. Ici pour l'vnement OnTruc la place de DeclencheTruc, nous la nommerons Truc.

Version-2 du code source


Unit UDesignEvent ; interface type EventTruc = procedure (Sender:TObject; info:string) of object ; ClassA = class private FOnTruc : EventTruc ; protected procedure Truc(s:string);virtual; // surchargeable dynamiquement public OnTruc : EventTruc read FOnTruc write FOnTruc ; end; implementation procedure ClassA.Truc(s:string);

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

554

begin if Assigned ( FOnTruc ) then FOnTruc (self , s) end; end.

Pour terminer, il nous reste dfinir un ou plusieurs gestionnaires possibles de l'vnement OnTruc (ici nous en avons mis quatre), et en connecter un la proprit OnTruc de l'objet de classe ClassA.

Nous dfinissons une classe ClasseUse qui utilise sur un objet de classe ClassA l'vnement OnTruc.

Version-3 du code source


Unit UDesignEvent ; interface type EventTruc = procedure (Sender:TObject; info:string) of object ; ClassA = class private FOnTruc : EventTruc ; protected procedure Truc(s:string);virtual; // surchargeable dynamiquement public ObjA : ClassA ; OnTruc : EventTruc read FOnTruc write FOnTruc ; procedure LancerTruc; // Declenche l'vnement OnTruc

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

555

end; ClasseUse = class public procedure method_100(Sender:TObject; info:string); procedure method_101(Sender:TObject; info:string); procedure method_102(Sender:TObject; info:string); procedure method_103(Sender:TObject; info:string); procedure principale; end; implementation {------------------- ClassA ------------------------} procedure ClassA.Truc(s:string); begin if Assigned ( FOnTruc ) then FOnTruc (self , s) end; procedure ClassA.LancerTruc ; begin .... Truc ("vnement dclench"); .... end; {------------------- ClasseUse ------------------------} procedure ClasseUse.principale; begin //.... ObjA := ClassA.Create ; ObjA.OnTruc := method_102 ; // connexion //.... ObjA.LancerTruc ; // lancement end; procedure ClasseUse.method_100(Sender:TObject; info:string); begin //.... end; procedure ClasseUse.method_101(Sender:TObject; info:string); begin //.... end; procedure ClasseUse.method_102(Sender:TObject; info:string); begin //.... end; procedure ClasseUse.method_103(Sender:TObject; info:string); begin //.... end; end.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

556

Code pratique : une pile Lifo vnementielle


Objectif : Nous livrons une classe de pile lifo hritant d'une Tlist (Un objet Tlist de Delphi, stocke un
tableau de pointeurs, utilis ici pour grer une liste d'objets) et qui est ractive l'empilement et au dpilement d'un objet. Nous suivons la dmarche prcdente en nous inspirant de son code final pour construire deux vnements dans la pile lifo et lui permettre de ragir ces deux vnements.

unit ULifoEvent ;

interface uses classes,Dialogs ;

Le type de l'vnement : type pointeur de mthode (2 paramtres)

type DelegateLifo = procedure ( Sender: TObject ; s :string ) of object ; ClassLifo = class (TList) Champs privs stockant la valeur de private l'vnement (pointeur de mthode). FOnEmpiler : DelegateLifo ; FOnDepiler : DelegateLifo ; public Evnement OnEmpiler : function Est_Vide : boolean ; - pointeur de mthode. procedure Empiler (elt : string ) ; procedure Depiler ( var elt : string ) ; property OnEmpiler : DelegateLifo read FOnEmpiler write FOnEmpiler ; property OnDepiler : DelegateLifo read FOnDepiler write FOnDepiler ; end; Evnement OnDepiler : ClassUseLifo = class - pointeur de mthode. public procedure EmpilerListener( Sender: TObject ; s :string ) ; procedure DepilerListener( Sender: TObject ; s :string ) ; constructor Create ; procedure main ; Si une mthode dont la signature est celle du type end; DelegateLifo est lie (gestionnaire de l'vnement OnDepiler), le champ FOnDepiler pointe vers elle, implementation il est donc non nul. Sinon FOnDepiler est nul (non assign) procedure ClassLifo.Depiler( var elt : string ) ; begin L'instruction FOnDepiler ( self ,elt ) sert appeler if not Est_Vide then self = la pile Lifo la mthode vers laquelle FOnDepiler pointe. begin elt :=string (self.First) ; self.Delete(0) ; self.Pack ; self.Capacity := self.Count ; Si une mthode dont la signature est celle du type if assigned(FOnDepiler) then DelegateLifo est lie (gestionnaire de l'vnement FOnDepiler ( self ,elt ) OnDepiler), le champ FOnEmpiler pointe vers elle, end il est donc non nul. end; Sinon FOnEmpiler est nul (non assign) procedure ClassLifo.Empiler(elt : string ) ; begin self.Insert(0 , PChar(elt)) ; if assigned(FOnEmpiler) then FOnEmpiler ( self ,elt ) end; L'instruction FOnEmpiler ( self ,elt ) sert appeler la mthode vers laquelle FOnEmpiler pointe.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

557

function ClassLifo.Est_Vide : boolean ; begin result := self.Count = 0 ; end; { ClassUseLifo } constructor ClassUseLifo.Create ; begin inherited; end; Classe de test crant une pile Lifo

Gestionnaire de l'vnement OnDepiler : signature compatible avec DelegateLifo.

procedure ClassUseLifo.DepilerListener( Sender: TObject ; s :string ) ; begin writeln ( 'On a depile : ' ,s) ; Gestionnaire de l'vnement OnEmpiler : end; signature compatible avec DelegateLifo. procedure ClassUseLifo.EmpilerListener( Sender: TObject ; s :string ) ; begin writeln ( 'On a empile : ' ,s) ; end; Mthode main de test procedure ClassUseLifo.main ; var pileLifo : ClassLifo ; Instanciation d'une ch :string ; pile Lifo tester. begin Affectation de chaque gestionnaire pileLifo := ClassLifo.Create ; l'vnement qu'il est charg de grer. pileLifo.OnEmpiler := EmpilerListener ; pileLifo.OnDepiler := DepilerListener ; pileLifo.Empiler( '[ eau ]' ) ; pileLifo.Empiler( '[ terre ]' ) ; Empilement de 4 lments pileLifo.Empiler( '[ mer ]' ) ; pileLifo.Empiler( '[ voiture ]' ) ; writeln ( 'Depilement de la pile :' ) ; while not pileLifo.Est_Vide do begin Dpilement de toute la pile pileLifo.Depiler(ch) ; writeln (ch) ; end; writeln ( 'Fin du depilement.' ) ; readln ; end; end. Application console Project2.dpr instanciant un objet de ClassUseLifo et lanant le test de la pile lifo par invocation de la mthode main.

program Project2; {$APPTYPE CONSOLE} uses SysUtils , UlifoEvent ; var execLifo : ClassUseLifo; begin execLifo := ClassUseLifo.Create; execLifo.main end. excution

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

558

Exemple vnementiel : un diteur de texte


1. L'nonc et les choix
Nous souhaitons dvelopper rapidement un petit diteur de texte qui nous permettra : de lire du texte partir d'un fichier sur disque ou sur disquette (ouvrir), de taper du texte (nouveau), de visualiser le texte entr, deffectuer sur ce texte les oprations classiques de copier/ coller/ couper, de le sauvegarder sur disque ou sur disquette (enregistrer). Les objets potentiels ragiront ces vnements selon le graphe ci-dessous

Lobjet TextEditeur est lobjet central sur lequel agissent tous les autres objets, il contiendra le texte diter. En faisant ressortir les oprations effectuer, lutilisation de la notion dabstraction est naturelle. Nous envisageons les actions suivantes obtenues par raction un vnement Click de souris (choix des objets du graphe prcdent): nouveau (utilise un objet dfinir) couper (utilise un objet dfinir)
Les bases de linformatique - programmation - ( rv. 04.01.2005 ) page

559

copier (utilise un objet dfinir) coller (utilise un objet dfinir) ouvrir (utilise un objet de dialogue) enregistrer (utilise un objet de dialogue) quitter (utilise un objet prdfini Form)

2. Les objets de composants


Delphi tant orient objet nous allons exploiter compltement l'analyse prsente dans le graphe vnementiel ci-haut en mettant en place quatre objets du genre composants visuels ou non visuels de Delphi.

Linterface choisie
Une fiche (Form1) comportant : Un Tmemo avec deux ascenseurs

Trois composants non visuels : TMainmenu (une barre de 2 menus) TopenDialog (pour le chargement de fichier) TSaveDialog (pour la sauvegarde d'un texte)

Le composant TMainmenu(1er menu) comporte un premier menu Fichier 5 items

Le composant TMainmenu (2me menu) comporte un deuxime menu Edition 3 items.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

560

Les menus dans la barre et les sous-menus sont tous des objets de classe TmenuItem qui sont grs travers le champ Items d'un objet de classe TMainMenu :

Chacun des 3 items est associ un raccourci clavier classique (Ctrl+...)

object MainMenu1: TMainMenu . object fichier1: TMenuItem Caption = 'fichier' end object edition1: TMenuItem Caption = 'edition' object couper1: TMenuItem Caption = 'couper' end object copier1: TMenuItem Caption = 'copier' end object coller1: TMenuItem Caption = 'coller' end end end ..

Correspondance entre le code cach par Delphi et l'inclusion des objets de TmenuItem dans un TmainMenu.

Mise en place de la gestion des vnements.


A chacun des items utilisables de chacun des 2 menus, il nous faut associer un gestionnaire dvnement qui indique au programme comment il doit ragir lorsque l'utilisateur slectionne un champ de l'un des menus par un click de souris. Nous avons vu que Delphi contient le mcanisme d'association des vnements nos gestionnaires. Beaucoup de contrles (classes visuelles)et beaucoup d'autres classes non visuelles comme les TMenuItem, de Delphi sont sensibles lvnement de click de souris : property OnClick : TnotifyEvent.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

561

Les gestionnaires de lvnement OnClick pour les TMenuItem


Voici les en-ttes des 7 gestionnaires de OnClick automatiquement construits:

procedure Nouveau1Click(Sender: TObject); procedure Ouvrir1Click(Sender: TObject); procedure Enregistrersous1Click(Sender: TObject); procedure Quitter1Click(Sender: TObject); procedure Couper1Click(Sender: TObject); procedure Copier1Click(Sender: TObject); procedure Coller1Click(Sender: TObject);

Voici pour chaque gestionnaire le code crit par le programmeur. Le code du gestionnaire Quitter1Click
procedure TForm1.Quitter1Click(Sender: TObject); begin Close; //crit par le dveloppeur (fermeture de la fentre) end;

Le code du gestionnaire Ouvrir1Click


procedure TForm1.Ouvrir1Click(Sender: TObject); begin if OpenDialog1.Execute then //crit par le dveloppeur begin Enregistrersous1.enabled:=true; TextEditeur.Lines.LoadFromFile(OpenDialog1.FileName); end end;

Le code du gestionnaire Enregistrersous1Click


procedure TForm1.Enregistrersous1Click(Sender: TObject); begin if SaveDialog1.Execute then // crit par le dveloppeur begin Enregistrersous1.enabled:=false; TextEditeur.Lines.SaveToFile( SaveDialog1.FileName ); end end;

Le code du gestionnaire Couper1Click


procedure TForm1.Couper1Click(Sender: TObject); begin TextEditeur.CutToClipboard; //crit par le dveloppeur end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

562

Le code du gestionnaire Copier1Click


procedure TForm1.Copier1Click(Sender: TObject); begin TextEditeur.CopyToClipboard; //crit par le dveloppeur end;

Le code du gestionnaire Coller1Click


procedure TForm1.Coller1Click(Sender: TObject); begin TextEditeur.PasteFromClipboard; //crit par le dveloppeur end;

Le code du gestionnaire Nouveau1Click


procedure TForm1.Nouveau1Click(Sender: TObject); begin TextEditeur.Clear; &not; crit par le dveloppeur Enregistrersous1.enabled:=true &not; crit par le dveloppeur end;

Il est noter que nous avons crit au total 16 lignes de programme Delphi pour construire notre micro-diteur. Ceci est rendu possible par la rutilisabilit de mthodes dj intgres dans les objets de Delphi et en fait prsentes dans le systme Windows. Vous pouvez voir la puissance de ce RAD lorsque vous observez par exemple l'instruction qui a permis de faire excuter le "copier" ou le "chargement d'un fichier" : TextEditeur.CopyToClipboard; La mthode CopyToClipboard s'applique l'objet TextEditeur qui est de la classe TMemo; cette instruction correspond un ensemble complexe d'oprations de bas niveau : le TMemo autorise une suite complexe d'oprations permettant de slectionner un texte crit sur plusieurs lignes du TMemo. Il les affiche en surbrillance et la mthode CopyToClipboard rcupre le texte slectionn puis le recopie enfin dans le presse-papier du systme.

TextEditeur.Lines.LoadFromFile(OpenDialog1.FileName); Nous n'avons par ailleurs eu aucun code particulier crire pour le chargement de fichier texte, la mthode LoadFromFile prsente dans l'objet Lines (de classe TStrings) effectue toutes les actions.

A titre de travail personnel il est recommand d'enrichir ce micro-diteur avec la possibilit de changer la police de caractre, la couleur du fond etc

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

563

5.6 Programmation dfensive


(les exceptions)
Plan du chapitre:

Introduction 1.Notions de dfense et de protection


1.1 Outils participant la programmation dfensive 1.2 Rle et mode daction dune exception 1.3 Gestion de la protection du code Fonctionnement sans incident Fonctionnement avec incident 1.4 Effets dus la position du bloc except...end Fonctionnement sans incident Fonctionnement avec incident 1.5 Interception dune exception dune classe donne 1.6 Ordre dans linterception dune exception Interception dans lordre de la hirarchie Interception dans lordre inverse

2. Traitement dun exemple de protections


2.1 Le code de dpart de lunit 2.2 Code de la version.1 (premier niveau de scurit) 2.3 Code de la version.2 (deuxime niveau de scurit)

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

564

Introduction
Nous allons montrer comment on peut concevoir la programmation dfensive en protgeant directement le code laide de la notion dexception (semblable celle du C++ ou dAda). Lobjectif principal est damliorer la qualit de " robustesse " (dfinie par B.Meyer) dun logiciel. Lutilisation des exceptions avec leur mcanisme intgr, autorise la construction rapide et nanmoins efficace de logiciels robustes.

Rappelons au lecteur que la scurit d'une application est susceptible d'tre mise mal par toute une srie de facteurs :

les problmes lis au matriel : par exemple la perte subite d'une connection un port, un disque dfectueux... les actions imprvues de l'utilisateur, entrainant par exemple une division par zro...

1. Notions de dfense et de protection


A loccasion de la traduction Algorithme langage volu comme pascal, nous avons rpertori en plus des actions algorithmiques, des actions de scurit et des actions ergonomiques qui doivent elles aussi tre programmes. La partie ergonomie est incluse dans la notice consacre aux interfaces de communication logiciel-utilisateur. La partie scurit a dj t aborde ailleurs, nous regroupons ici ce que nous devons connatre. Pour obtenir une certaine " robustesse " dans nos programmes nous savons dj que la scurit doit porter au moins sur :

les domaines de dfinitions des donnes, les contraintes dimplantation, le filtrage des saisies, les problmes de transtypage

Toutefois les faiblesses dans un logiciel pendant son excution, peuvent survenir : lors des entres-sorties, lors de calculs mathmatiques interdits (comme la division par zro), lors de fausses manoeuvres de la part de lutilisateur, ou encore lorsque la connexion un priphrique est inopinment interrompue. La programmation dfensive est plus une attitude de pense et de comportement quune nouvelle mthode. Cette attitude consiste prvoir que le logiciel sera soumis des dfaillances dues certains paramtres externes ou internes et donc prvoir une rponse adapte chaque type de situation.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

565

La comparaison des cots de diffrents ratios de productivit tablie par B.Boehm, montre que lexigence de fiabilit est lune des plus chres (surcot de 87%). Cette remarque pourrait en apparence nous conduire croire que ce facteur est donc une affaire de spcialistes et ne constitue pas une proccupation dans un discours dinitiation. Nous allons voir quil nen est rien et quen fait notre mthode de travail et les outils que nous utilisons concourent une attitude de programmation dfensive sans que nous contraignions fortement notre pense en ce sens. Nous pensons enfin quil est bon dinduire dans lesprit du dveloppeur en programmation visuelle dbutant des ides fondes sur des pratiques mthodiques qui lui viteront lcueil de " lart indisciplin " du logiciel, mais qui pourraient lui donner le got de continuer dans cette discipline.

1.1 Outils participant la programmation dfensive Voici cinq secteurs dactivit parmi ceux que nous connaissons, participant une mthode de programmation dfensive.

La modularit Le principe du dcoupage en modules restreint la propagation des effets perturbateurs sur dautres modules partir dune erreur survenant dans un module donn.

Lencapsulation Associe la modularit, elle protge les constituants internes dun module (champs et mthodes).

Les TAD (types abstraits) En fournissant un outil de spcification des donnes avec des prconditions sur la validit des oprateurs, un TAD assure la description des vrifications de domaines.

Lutilisation de mthodes systmatiques Comme lalgorithmique, la programmation par la syntaxe, les machines abstraites, les gnrateurs dautomates,... ces outils encouragent ltudiant sessayer une programmation sre.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

566

Lutilisation dun RAD visuel comme Delphi Ce genre de systme de dveloppement apporte un certains nombres davantages en la matire : il autorise la mise en uvre des cinq secteurs prcdents dactivit, il fournit au programmeur des kits dobjets scuriss et rutilisables, il permet de construire rapidement des interfaces qui participent une meilleure dfense du logiciel contre des actions non valides (par exemple en utilisant la mthode de squencement par plans daction).

A ct de cet ventail doutils intgrant en gnral la notion de programmation dfensive, il existe un outil spcifique ddi ce genre de programmation : les exceptions.

1.2 Rle et mode daction dune exception

Rle dune exception


Rserv jusqu' prsent aux spcialistes en Ada, en C++ ou en Java, cet outil est mis dans le RAD Delphi la porte du dbutant. Comme son nom lindique, une exception est charge de signaler un comportement exceptionnel (mais prvu) dune partie spcifique dun logiciel. Dans les langages de programmation actuels, les exceptions font partie du langage lui-mme. Cest le cas de Delphi qui intgre les exceptions comme une classe particulire : la classe Exception. Cette classe contient un nombre important de classes drives.

Comment agit une exception


Ds quune erreur se produit comme un manque de mmoire , un calcul impossible, un fichier inexistant, un transtypage non valide,..., un objet de la classe adquate drive de la classe Exception est instanci. Nous dirons que le logiciel " dclenche une exception ". Exemple : soit une saisie dun entier dans un Tedit nomm Editsaisie. Objets visuels : Editsaisie: TEdit; Editresultat: TEdit; Button1: TButton; Actions : Lutilisateur entre un entier dans Editsaisie, il clique sur le bouton Button1 qui effectue un transtypage dans une variable locale " n : integer " puis il se dsactive et le Tedit Editresultat, change de couleur.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

567

Le gestionnaire dvnement clic de Button1 est alors le suivant :


procedure TForm1.Button1Clic(Sender: TObject); var n:integer; begin Editresultat.color:=clAqua; n:=StrtoInt(Editsaisie.text); Editresultat.color:=clyellow; Editresultat.text:= Editsaisie.text; Editsaisie.clear ; end;

Une excution sans incident donne ceci :

avant clic sur Button1

aprs clic sur Button1

Lors de lexcution, supposons que nous entrons dans Editsaisie la chane " asa12324 " qui nest pas un entier. La fonction StrtoInt dclenche une exception et nous envoie un message derreur gnral sur lincident qui vient de se produire : (aprs clic sur Button1 Message derreur )

En outre, lincident a arrt lexcution du code dans le gestionnaire Button1Clic. Le code a t excut normalement jusqu' linstruction de transtypage qui a dclench lexception. Le reste des lignes de code a t ignor :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

568

Si nous voulons que le message soit plus explicite, ou si nous voulons par exemple que malgr tout une certaine partie du code sexcute en fournissant des valeurs par dfaut malgr lincident, nous devons grer nous-mmes cette exception. Afin de pouvoir grer une exception dclenche, il nous faut disposer dun gestionnaire dexception qui permette de traiter tous les types dexception.

1.3 Gestion de la protection du code Le langage Delphi contient un mcanisme appel gestionnaire dexception qui sinsre dans les lignes de code l o nous souhaitons assurer une protection. Syntaxe du gestionnaire : mots clefs (try, except) try - ... <lignes de code protger> - ... except - ... <lignes de code ragissant lexception> - ... end ;

Principe de fonctionnement dun tel gestionnaire :


Ds quune exception est dclenche dans le bloc de lignes compris entre try....except, il y a droutement de lexcution (arrt dexcution squentielle du code) vers la premire ligne du bloc except...end et lexcution continue squentiellement partir de cet endroit. Reprenons lexemple prcdent lgrement modifi dans le code du gestionnaire du clic de Button1.
procedure TForm1.Button1Clic(Sender: TObject); var n:integer; begin Editresultat.color:=clAqua; n:=StrtoInt(Editsaisie.text); Editresultat.color:=clyellow; Editresultat.text:= inttostr(n); Editsaisie.clear ; end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

569

Mettons en place une protection de linstruction incrimine, tout en conservant lexcution des lignes de code suivantes. Comme la variable " n " naura pas de valeur cause de lincident, nous lui attribuons la valeur zro par dfaut si un incident se produit.
procedure TForm1.Button1Clic(Sender: TObject); var n:integer; begin try Editresultat.color:=clAqua; n:=StrtoInt(Editsaisie.text); except showmessage('tapez un entier (zro par dfaut !'); n:=0 end; Editresultat.color:=clyellow; Editresultat.text:= inttostr(n); Editsaisie.clear ; end;

1.3.1 - Fonctionnement sans incident :


(Lgende : la flche indique lexcution squentielle de la ligne de code devant laquelle elle est place).

Les lignes de code sont excutes squentiellement sauf le bloc except...end (qui nest excut quen cas dincident).

1.3.2 - Fonctionnement avec incident :


Nous entrons dans Editsaisie comme prcdemment une valeur non entire.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

570

Message envoy par la fonction Showmessage dans le bloc except...end. Ensuite le code continue sexcuter en squence partir de n :=0 ;...

Suite du droulement squentiel de lexcution dans le bloc exceptend :

En fait dans cet exemple, nimporte quelle exception dclenche dans le bloc tryexcept droute vers le bloc exceptend.

1.4 Effets dus la position du bloc except...end Afin de bien comprendre cette notion de droutement (dont le placement est la charge du programmeur) observons ce quapporte une modification de la place du bloc except...end au droulement du code pendant lexcution. Soit, dans le mme exemple, le nouveau code dans Button1Clmick o nous avons repouss le bloc except...end la fin.
procedure TForm1.Button1Clic(Sender: TObject); var n:integer; begin try Editresultat.color:=clAqua; n:=StrtoInt(Editsaisie.text); Editresultat.color:=clyellow; Editresultat.text:= inttostr(n); Editsaisie.clear ; except showmessage('tapez un entier (zro par dfaut !'); n:=0 end; end;

Puis excutons le programme.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

571

1.4.1 - Fonctionnement sans incident :


Identique au prcdent paragraphe, le bloc except...end tant ignor.

1.4.2 - Fonctionnement avec incident :


(Lgende : la flche indique lexcution squentielle de la ligne de code devant laquelle elle est place).

le code continue son droulement dans le bloc except...end en " sautant " trois instructions.

Etat final des rsultats aprs traitement de lexception : les deux Tedit Editresultat et Editsaisie nont pas chang puisque les instructions: Editresultat.color:=clyellow; Editresultat.text:= inttostr(n); Editsaisie.clear ; nont pas t excutes, par suite du droutement du code.

Nous notons que cette mthode de droutement du code est trs proche du fonctionnement dune machine de Von Neumann. Nous venons de voir comment intercepter une exception quelconque sans savoir exactement sa catgorie. Nous pouvons en fait intercepter une exception dune manire encore plus " fine " avec le gestionnaire try...except...end. Il nous permet de slectionner la classe exacte de lexception et de ne faire fonctionner le droutement du code que pour une exception dfinie lavance.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

572

1.5 Interception dune exception dune classe donne

Diagrammes de syntaxe du gestionnaire :


<instruction try> :

<Bloc dexception> :

<gestionnaire dexception> :

Diffrentes classes dexception Delphi


Ci-dessous la hirarchie des classes dexception, qui drivent toutes de la classe Exception:

Exemple dcriture d'un gestionnaire : try <lignes de code protger> except On EConvertError do begin <lignes de code ragissant lexception EConvertError >

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

573

end ; On EintError do begin <lignes de code ragissant lexception EintError > end ; else begin <lignes de code ragissant dautres exceptions > end ; end ;

Principe de fonctionnement dun tel gestionnaire


Ds quune exception est dclenche dans le bloc de lignes compris entre try....except, il y a droutement de lexcution (arrt dexcution squentielle du code) vers le bloc except...end. Le slecteur de gestionnaire dexception on...do fonctionne approximativement comme un case...of, en nexcutant que le champ slectionn. Supposons que lexception leve soit de la classe EintError ; linstruction try nexcute alors que le code du " bon " gestionnaire en loccurrence : On EintError do begin <lignes de code ragissant lexception EintError > end ; Puis lexcution se poursuit aprs le end du bloc except...end.

1.6 Ordre dans linterception dune exception A la diffrence dun "case of" pascal, le choix du slecteur de gestionnaire (on...do) seffectue squentiellement dans lordre dcriture des lignes de code. On choisira donc, lorsquil y a une hirarchie entre les exceptions intercepter, de placer le code de leurs gestionnaires dans lordre inverse de la hirarchie. Exemple : division par zro dans un calcul en virgule flottante EMathError est la classe des exceptions pour les erreurs de calcul.

EZeroDivide indique la division par zro dans une telle opration. Programmons un calcul partir dun bouton :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

574

procedure TForm1.Button1Clic(Sender: TObject); var x,y,z:real; begin try x:=StrtoFloat(Edit1.text); y:=StrtoFloat(Edit2.text); z:=x /y ; Edit3.text:=FloattoStr(z); except ............ ............ end; end; Au dpart nous avons edit1.text = 12,875 et edit2.text 0. Le calcul est erron car x vaut 12,85 et y vaut zro ce qui va induire une erreur de division par zro dans linstruction z := x / y. Observons ce qui se passe lorsque nous interceptons les exceptions EMathError et EZeroDivide.

1.6.1 - Interception dans lordre de la hirarchie :


La slection dexception est programme dans lordre de la hirarchie des classes : EMathError |____ EZeroDivide

procedure TForm1.Button1Clic(Sender: TObject); var x,y,z:real; begin try x:=StrtoFloat(Edit1.text); y:=StrtoFloat(Edit2.text); z:=x /y ; Edit3.text:=FloattoStr(z); except on EMathError do Edit3.text:='Erreur gnrale'; on EZeroDivide do Edit3.text:='division par zro'; end; end;

EMathError est intercepte en premier.

1.6.2 - Interception dans lordre inverse :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

575

La slection dexception est programme dans lordre inverse de la hirarchie des classes.

procedure TForm1.Button1Clic(Sender: TObject); var x,y,z:real; begin try x:=StrtoFloat(Edit1.text); y:=StrtoFloat(Edit2.text); z:=x /y ; Edit3.text:=FloattoStr(z); except on EZeroDivide do Edit3.text:='division par zro'; on EMathError do Edit3.text:='Erreur gnrale'; end; end;

Cest EZeroDivide qui est intercepte en premier.

2. Traitement dun exemple de protections


Reprenons comme base le premier exemple tudi dans le chapitre sur les interfaces. Supposons que nous voulons largir notre interface de calcul aux oprations entires : Mutiplication, Division, Addition, Soustraction, Quotient, Reste. Nous limiterons nos entiers au type Smallint Delphi identique au type integer du pascal (Smallint = -32768..32767, sign sur 16 bits). Interface retenue

Editnbr1: TEdit; Editnbr2: TEdit; Editmessage: TEdit; Editresult: TEdit; ListBoxOperation: TListBox; ButtonCalcul: TBitBtn; Labeltypoperat: TLabel;

2.1 Le code de dpart de lunit


Les bases de linformatique - programmation - ( rv. 04.01.2005 ) page

576

Champ priv de la classe Tform1 : Toper:array[0..5]of string; implementation Le tableau Toper contient les symboles des oprateurs entiers, il est initialis lors de lactivation de la fiche
procedure TForm1.FormActivate(Sender: TObject); begin Toper[0]:='*'; Toper[1]:='/'; Toper[2]:='+'; Toper[3]:='-'; Toper[4]:=' div '; Toper[5]:=' mod '; end;

Lutilisateur choisit par slection dans le ListBoxOperation lopration quil veut effectuer ; ltiquette Labeltypoperat affiche le symbole associ :
procedure TForm1.ListBoxOperationClic(Sender: TObject); begin Labeltypoperat.caption:=Toper[ListBoxOperation.ItemIndex]; end;

Les deux Edit de saisie Editnbr1 et Editnbr2 sont sensibles lvnement OnChange qui permet de dverrouiller le bouton de calcul :
procedure TForm1.Editnbr1Change ( Sender : TObject); begin ButtonCalcul.enabled:=true; end; procedure TForm1.Editnbr2Change ( Sender : TObject); begin ButtonCalcul.enabled:=true; end;

Une fois que les entiers sont entrs et le genre dopration slectionn, le ButtonCalcul lance le calcul sur un clic de lutilisateur :
procedure TForm1.ButtonCalculClic(Sender: TObject); var op1,op2,result:smallint; begin ButtonCalcul.enabled:=false; op1:=strtoint(Editnbr1.text); op2:=strtoint(Editnbr2.text); case ListBoxOperation.ItemIndex of 0: result:=op1 * op2; 1: result:=trunc(op1 / op2); 2: result:=op1 + op2; 3: result:=op1 - op2; 4: result:=op1 div op2; 5: result:=op1 mod op2; end; Editresult.text:=inttostr(result);

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

577

Editmessage.text:=inttostr(op1)+Toper[ListBoxOperation.ItemIndex] +' '+inttostr(op2)+'= '+Editresult.text; end;

A ce stade la saisie nest pas encore scurise. Afin que le lecteur puisse retrouver les lments dj traits dans le chapitre sur les interfaces, nous reprenons comme premier niveau de scurit le mme genre de programmation : synchronisation des 3 objets de saisie Editnbr1, Editnbr2 et ListBoxOperation, puis programmation par plans daction.

2.2 Code de la version.1 (premier niveau de scurit) Champs privs de la classe Tform1: oper1,oper2,operat:boolean; //les 3 drapeaux Toper:array[0..5]of string; implementation Le tableau Toper contient les symboles des oprateurs entiers, il est initialis lors de lactivation de la fiche (pas dajout de code ni de changement). Ajout de la mthode RAZtout positionnant linterface son tat initial (correspondant la table des tats initiaux) :
procedure TForm1.RAZTout; begin ButtonCalcul.enabled:=false; Editnbr1.clear; Editnbr2.clear; Editresult.clear; Editmessage.clear; oper1:=false; oper2:=false; operat:=false; end;

Adjonction de la mthode TestEntrees charge de lancer lactivation deButtonCalcul si les trois drapeaux sont tous levs :
procedure TForm1.TestEntrees; begin if oper1 and oper2 and operat then ButtonCalcul.enabled:=true end;

Lutilisateur choisit par slection dans le ListBoxOperation lopration quil veut effectuer, ltiquette Labeltypoperat affiche le symbole associ. Adjonction dans le code du drapeau et du test :

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

578

procedure TForm1.ListBoxOperationClic(Sender: TObject); begin operat:=true; TestEntrees; Labeltypoperat.caption:=Toper[ListBoxOperation.ItemIndex]; end;

Les deux Edit de saisie Editnbr1 et Editnbr2 sont sensibles lvnement OnChange ; voici lajout du code de plans daction dans les gestionnaires de cet vnement :
procedure TForm1.Editnbr1Change(Sender: TObject); begin if Editnbr1.text<>'' then begin oper1:=true; TestEntrees; end else begin ButtonCalcul.enabled:=false; oper1:=false; // drapeau de Editnbr1 baiss end end; procedure TForm1.Editnbr12Change(Sender: TObject); begin if Editnbr2.text<>'' then begin oper2:=true; TestEntrees; end else begin ButtonCalcul.enabled:=false; oper2:=false; // drapeau de Editnbr2 baiss end end;

Le code du plan daction associ au ButtonCalcul reste strictement le mme. Nous proposons dans le paragraphe qui suit, un complment de scurit apport par des interceptions dexception.

2.3 Code de la version.2 (deuxime niveau de scurit) Tout le code de la version.1 reste identique dans la version.2, les adjonctions sont uniquement dans le gestionnaire du ButtonCalcul. Nous lanons les leves dexception lorsque les incidents ont lieu. Nous avons ajout une mthode signe qui renvoie +1 ou -1 selon le signe de lentier dentre et dune constante dentier maximum:
const Maxint=32767; function signe(n:smallint):smallint; begin if n>0 then signe:=1 else if n<0 then signe:=-1 else signe:=0 end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

579

Le code est protg par les exceptions suivantes :


procedure TForm1.ButtonCalculClic(Sender: TObject); var op1,op2,result:smallint; begin ButtonCalcul.enabled:=false; try op1:=strtoint(Editnbr1.text); except on ERangeError do if Editnbr1.text[1]='-' then op1:=-Maxint else op1:=Maxint; on EConvertError do op1:=Maxint; end; try op2:=strtoint(Editnbr2.text); except on EConvertError do op2:=Maxint; on ERangeError do if Editnbr2.text[1]='-' then op2:=-Maxint else op2:=Maxint; end; try case ListBoxOperation.ItemIndex of 0: result:=op1 * op2; 1: result:=trunc(op1 / op2); 2: result:=op1 + op2; 3: result:=op1 - op2; 4: result:=op1 div op2; 5: result:=op1 mod op2; end; except on EDivByZero do if ListBoxOperation.ItemIndex=4 then result:=signe(op1)*Maxint else result:=op1; on EZeroDivide do result:=signe(op1)*Maxint; on EIntOverFlow do result:=signe(op1)*signe(op2)*Maxint; end; Editresult.text:=inttostr(result); Editmessage.text:=inttostr(op1)+Toper[ListBoxOperation.ItemIndex] +' '+inttostr(op2)+'= '+Editresult.text; end;

Le lecteur modifiera les choix de valeurs par dfaut dans les gestionnaires dexception. Dans lexemple plus haut, ces choix ne sont quindicatifs et servent montrer que lon peut, soit arrter un calcul, soit le continuer avec une valeur de remplacement aprs signalement de lerreur. Il sassurera par lui-mme que la conjonction entre les plans daction et les exceptions est un systme de programmation dfensive efficace.

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

580

Crer et lancer ses propres exceptions

Il est possible de construire de nouvelle classe d'exceptions personnalises en hritant d'une des classes de Delphi mentionnes plus haut, ou minima de la classe de base Exception.(cette classe contient une proprit public property Message: string, qui contient en type string le texte afficher dans la bote de dialogue des exceptions quand l'exception est dclenche). Il est aussi possible de lancer une exception personnalise (comme si c'tait une exception propre Delphi) n'importe quel endroit dans le code d'une mthode d'une classe en instanciant un objet d'exception personnalis et en le prfixant du mot clef raise. Le mcanisme gnral d'interception des exceptions travers des gestionnaires d'exceptions tryexcept s'applique tous les types d'exceptions y compris les exceptions personnalises.

Cration d'une nouvelle classe

Type MonExcept = class (Exception) End; MonExcept hrite par construction de la proprit public Message de sa mre.

Lancer une MonExcept

Type MonExcept = class (Exception) End; Procedure classA.Truc; begin .. raise MonExcept.Create ( 'salut' ); .. end;

intercepter une MonExcept

MonExcept = class (Exception) end; Procedure classB.Meth; begin .. try.. // code protger except on MonExcept do begin .. // code de raction l'exception end; end; end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 )

page

581

Exercices chapitre 5
Ex-1 : Il est demand de construire une classe de pile lifo ClassLifo hritant d'une Tlist (Un objet Tlist de Delphi, stocke un tableau de pointeurs, utilis ici pour grer une liste d'objets) et qui est ractive l'empilement et au dpilement d'un objet. Nous proposons de suivre la dmarche de la notice mthodologique du cours en nous inspirant de son code final pour construire deux vnements dans la pile lifo et lui permettre de ragir ces deux vnements.

Ex-2 : Nous souhaitons dvelopper rapidement un petit diteur de texte qui nous permettra : de lire du texte partir d'un fichier sur disque ou sur disquette (ouvrir), de taper du texte (nouveau), de visualiser le texte entr, deffectuer sur ce texte les oprations classiques de copier/ coller/ couper, de le sauvegarder sur disque ou sur disquette (enregistrer).

Ex-3 : Nous reprenons la classe dj construite ClassLifo de pile lifo hritant d'une Tlist ractive l'empilement et au dpilement d'un objet, il est demand de la rendre plus robuste en lui permettant lorsque la pile est vide de lancer une exception dpilement impossible. Ex-4 : On dfinit la structure de donnes de liste chane double, qui est une liste chane pouvant se parcourir dans les deux sens, chaque maillon de la liste est li son suivant et son prcdent sauf les maillons situs aux extrmits de la liste; ( a1, , an ) sont les donnes de la liste :

Implanter en delphi la classe TListeDble reprsentant une telle liste chane double et TcellDble un maillon de la liste (un maillon est donc un objet de calesse TcellDble), l'information du maillon est une chane de caractres. TlisteDble =class public constructor Create; destructor Liberer; procedure AjouterLeft (elt:string); procedure AjouterRight (elt:string); procedure InsererLeft (rang:integer;elt:string); procedure InsererRight (rang:integer;elt:string); procedure SupprimerLeft (rang:integer); procedure SupprimerRight (rang:integer); function ElementFromLeft (rang:integer):string; function ElementFromRight (rang:integer):string; function IndexFromLeftOf (elt:string):integer; function IndexFromRightOf (elt:string):integer; function Tete:TCellDble; function Fin:TCellDble; function Longueur : integer; procedure Clear; function ParcourirLeft:string; private head , tail : TCellDble; end;

TCellDble = class public info:string; constructor Crer (avant , apres:TCellDble; elt:string); procedure InsererAvant (cell:TCellDble); procedure InsererApres (cell:TCellDble); private next:TCellDble; prec:TCellDble; end; Les mthodes InsererAvant et InsererApres ralisent l'insertion (avant l'objet ou aprs l'objet)

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

582

On propose pour simplifier l'criture des algorithmes de parcours de la liste de mettre deux sentinelles head et tail bornant les deux "bouts" de la liste ( cellules ne contenant de donnes significatives) :

Spcifications des mthodes implanter : constructor Create; Cre une liste vide :

destructor Liberer; procedure AjouterLeft (elt : string); procedure AjouterRight (elt : string); procedure InsererLeft ( rang:integer ; elt:string ); procedure InsererRight ( rang:integer ; elt:string ); procedure SupprimerLeft (rang:integer); procedure SupprimerRight (rang:integer); function ElementFromLeft (rang:integer):string; function ElementFromRight (rang:integer):string; function IndexFromLeftOf (elt : string):integer; function IndexFromRightOf (elt : string):integer; function Tete:TCellDble; function Fin:TCellDble; function Longueur : integer; procedure Clear;

Libre la mmoire utilise par la liste. Ajoute la donne elt: string aprs head. Ajoute la donne elt: string avant tail. Insre la donne elt: string au rang : integer , rang compt partir de head (parcours gauche). Insre la donne elt: string au rang : integer , rang compt partir de tail (parcours droite). Supprime la donne de rang : integer , compte partir de head (parcours gauche). Supprime la donne de rang : integer , compte partir de tail (parcours droite). Renvoie la donne de rang : integer , compte partir de head (parcours gauche). Renvoie la donne de rang : integer , compte partir de tail (parcours droite). Renvoie le rang de la position de la donne elt : string compt partir de head (parcours gauche). Renvoie le rang de la position de la donne elt: string compt partir de tail (parcours droite). Renvoie une rfrence sur head. Renvoie une rfrence sur tail. Fournit le nombre d'lments utiles de la liste. Remet la liste vide :

function ParcourirLeft : string;

Parcours des chanes de la liste de head tail en les concatnant entre elles et renvoie la chane unique obtenue.

Ex-5 : On dfinit la hirarchie suivante dans les figures gometriques : Un quadrilatre est une figure (A,B,C,D) possdant quatre cts. Un paralllogramme est un quadrilatre dont les cts opposs sont parallles et les angles opposs gaux. Un rectangle est un paralllogramme dont tous les angles ont la mme mesure : 90 Un carr est un rectangle dont tous les cts sont gaux.

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

583

Il est demand d'implanter en Delphi la hirarchie de classe selon les diagrammes UML ci-aprs :

Spcifications des mthodes implanter type cotes = string; Les noms des cts ou des sous forme de string angles ( cts angles = string; :"AB", "CD", ou angles : "ABC", "BCD",). function PropAngles (x:angles) : string; Renvoie dans une string les proprits d'un angle x : angles. function PropCotes (x:cotes) : string; Renvoie dans une string les proprits d'un ct x : cotes. procedure AfficheCotes (List : TlistBox); Affiche dans un TlistBox les proprits des 4 cts. procedure AfficheAngles (List : TlistBox); Affiche dans un TlistBox les proprits des 4 angles. Il est demand de construire une interface visuelle de test d'un objet de classe quadrilatre instanci la demande selon l'une des trois classes filles (exemple ci-dessous d'une instanciation d'un quadrilatre en carr):

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

584

Ex-6 : Vous aurez utiliser la classe TTimer qui encapsule les fonctions de timer de l'API Windows, on rappelle les proprits utiles que cette classe contient : property Enabled: Boolean; // Dtermine si le timer rpond aux vnements timer. property Interval: Cardinal; // Dtermine l'intervalle de temps, exprim en millisecondes, s'coulant avant que le composant timer gnre un autre vnement OnTimer. property OnTimer: TNotifyEvent; // Se produit quand le temps spcifi par la proprit Interval s'est coul. unit UClassclickMemo; // classe TMemoFlash interface uses stdctrls, extctrls, Graphics, classes, controls; type TMemoFlash = class () public private end; implementation end. Questions : Construire une classe visuelle complte TMemoFlash hrite des TMemo qui clignote 10 fois (il changera de couleur jaune-bleu, par intermittence de 100ms entre chaque flash) lorsque l'utilisateur clique avec la souris dans le composant. Un TMemoFlash doit avoir automatiquement comme parent son propritaire et lors de sa cration il affichera l'adresse mmoire de la fentre de son parent et celle de sa propre fentre.

Ex-7 : construire une IHM de filtrage d'un texte entr au clavier dans un TEdit et recopi dans un TMemo une fois filtr :

Texte brut entr au clavier dans le TEdit : EditSaisie.

Texte recopi une fois filtr dans le TEdit : EditFiltrage. Le filtrage consiste ne conserver dans EditFiltrage que les lettres majuscules et minuscules, et exclure tout autre caractre lors de la recopie du texte entr dans EditSaisie. Le filtrage doit s'effectuer la vole (c'est dire au fur et mesure que l'on tape du texte au clavier dans EditSaisie) et lorsque l'utilisateur appui sur la touche entre du clavier le texte qui a t filtr doit tre rang dans un TMemo nomm MemoApresFiltrage. Prvoir deux versions possibles selon que l'utilisateur est autoris utiliser la touche d'effacement arrire (backspace) ou non dans la saisie du texte et utiliser l'vnement OnKeypress pour effectuer le filtrage la vole.

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

585

Ex-1 Code solution pratique : une pile Lifo vnementielle

unit ULifoEvent ;

interface uses classes,Dialogs ;

Le type de l'vnement : type pointeur de mthode (2 paramtres)

type DelegateLifo = procedure ( Sender: TObject ; s :string ) of object ; ClassLifo = class (TList) Champs privs stockant la valeur de private l'vnement (pointeur de mthode). FOnEmpiler : DelegateLifo ; FOnDepiler : DelegateLifo ; public Evnement OnEmpiler : function Est_Vide : boolean ; - pointeur de mthode. procedure Empiler (elt : string ) ; procedure Depiler ( var elt : string ) ; property OnEmpiler : DelegateLifo read FOnEmpiler write FOnEmpiler ; property OnDepiler : DelegateLifo read FOnDepiler write FOnDepiler ; end; Evnement OnDepiler : ClassUseLifo = class - pointeur de mthode. public procedure EmpilerListener( Sender: TObject ; s :string ) ; procedure DepilerListener( Sender: TObject ; s :string ) ; constructor Create ; procedure main ; Si une mthode dont la signature est celle du type end; DelegateLifo est lie (gestionnaire de l'vnement OnDepiler), le champ FOnDepiler pointe vers elle, implementation il est donc non nul. Sinon FOnDepiler est nul (non assign) procedure ClassLifo.Depiler( var elt : string ) ; begin L'instruction FOnDepiler ( self ,elt ) sert appeler if not Est_Vide then self = la pile Lifo la mthode vers laquelle FOnDepiler pointe. begin elt :=string (self.First) ; self.Delete(0) ; self.Pack ; self.Capacity := self.Count ; Si une mthode dont la signature est celle du type if assigned(FOnDepiler) then DelegateLifo est lie (gestionnaire de l'vnement FOnDepiler ( self ,elt ) OnDepiler), le champ FOnEmpiler pointe vers elle, end il est donc non nul. end; Sinon FOnEmpiler est nul (non assign) procedure ClassLifo.Empiler(elt : string ) ; begin self.Insert(0 , PChar(elt)) ; if assigned(FOnEmpiler) then FOnEmpiler ( self ,elt ) end; L'instruction FOnEmpiler ( self ,elt ) sert appeler la mthode vers laquelle FOnEmpiler pointe.

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

586

function ClassLifo.Est_Vide : boolean ; begin result := self.Count = 0 ; end; { ClassUseLifo } constructor ClassUseLifo.Create ; begin inherited; end; Classe de test crant une pile Lifo

Gestionnaire de l'vnement OnDepiler : signature compatible avec DelegateLifo.

procedure ClassUseLifo.DepilerListener( Sender: TObject ; s :string ) ; begin writeln ( 'On a depile : ' ,s) ; Gestionnaire de l'vnement OnEmpiler : end; signature compatible avec DelegateLifo. procedure ClassUseLifo.EmpilerListener( Sender: TObject ; s :string ) ; begin writeln ( 'On a empile : ' ,s) ; end; Mthode main de test procedure ClassUseLifo.main ; var pileLifo : ClassLifo ; Instanciation d'une ch :string ; pile Lifo tester. begin Affectation de chaque gestionnaire pileLifo := ClassLifo.Create ; l'vnement qu'il est charg de grer. pileLifo.OnEmpiler := EmpilerListener ; pileLifo.OnDepiler := DepilerListener ; pileLifo.Empiler( '[ eau ]' ) ; pileLifo.Empiler( '[ terre ]' ) ; Empilement de 4 lments pileLifo.Empiler( '[ mer ]' ) ; pileLifo.Empiler( '[ voiture ]' ) ; writeln ( 'Depilement de la pile :' ) ; while not pileLifo.Est_Vide do begin Dpilement de toute la pile pileLifo.Depiler(ch) ; writeln (ch) ; end; writeln ( 'Fin du depilement.' ) ; readln ; end; end. Application console Project2.dpr instanciant un objet de ClassUseLifo et lanant le test de la pile lifo par invocation de la mthode main.

program Project2; {$APPTYPE CONSOLE} uses SysUtils , UlifoEvent ; var execLifo : ClassUseLifo; begin execLifo := ClassUseLifo.Create; execLifo.main end. excution

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

587

Ex-2 Solution dtaille : un diteur de texte

1. Les choix partir de l'nonc


Les objets potentiels ragiront ces vnements selon le graphe ci-dessous

Lobjet TextEditeur est lobjet central sur lequel agissent tous les autres objets, il contiendra le texte diter. En faisant ressortir les oprations effectuer, lutilisation de la notion dabstraction est naturelle. Nous envisageons les actions suivantes obtenues par raction un vnement Click de souris (choix des objets du graphe prcdent):

nouveau (utilise un objet dfinir) couper (utilise un objet dfinir) copier (utilise un objet dfinir) coller (utilise un objet dfinir) ouvrir (utilise un objet de dialogue) enregistrer (utilise un objet de dialogue) quitter (utilise un objet prdfini Form)

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

588

2. Les objets de composants


Delphi tant orient objet nous allons exploiter compltement l'analyse prsente dans le graphe vnementiel cihaut en mettant en place quatre objets du genre composants visuels ou non visuels de Delphi.

Linterface choisie
Une fiche (Form1) comportant : Un Tmemo avec deux ascenseurs

Trois composants non visuels : TMainmenu (une barre de 2 menus) TopenDialog (pour le chargement de fichier) TSaveDialog (pour la sauvegarde d'un texte)

Le composant TMainmenu(1er menu) comporte un premier menu Fichier 5 items

Le composant TMainmenu (2me menu) comporte un deuxime menu Edition 3 items.

Les menus dans la barre et les sous-menus sont tous des objets de classe TmenuItem qui sont grs travers le champ Items d'un objet de classe TMainMenu :

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

589

Chacun des 3 items est associ un raccourci clavier classique (Ctrl+...)

object MainMenu1: TMainMenu . object fichier1: TMenuItem Caption = 'fichier' end object edition1: TMenuItem Caption = 'edition' object couper1: TMenuItem Caption = 'couper' end object copier1: TMenuItem Caption = 'copier' end object coller1: TMenuItem Caption = 'coller' end end end ..

Correspondance entre le code cach par Delphi et l'inclusion des objets de TmenuItem dans un TmainMenu.

Mise en place de la gestion des vnements.


A chacun des items utilisables de chacun des 2 menus, il nous faut associer un gestionnaire dvnement qui indique au programme comment il doit ragir lorsque l'utilisateur slectionne un champ de l'un des menus par un click de souris. Nous avons vu que Delphi contient le mcanisme d'association des vnements nos gestionnaires. Beaucoup de contrles (classes visuelles)et beaucoup d'autres classes non visuelles comme les TMenuItem, de Delphi sont sensibles lvnement. de click de souris : property OnClick : TnotifyEvent.

Les gestionnaires de lvnement OnClick pour les TMenuItem


Voici les en-ttes des 7 gestionnaires de OnClick automatiquement construits :

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

590

procedure Nouveau1Click(Sender: TObject); procedure Ouvrir1Click(Sender: TObject); procedure Enregistrersous1Click(Sender: TObject); procedure Quitter1Click(Sender: TObject); procedure Couper1Click(Sender: TObject); procedure Copier1Click(Sender: TObject); procedure Coller1Click(Sender: TObject);

Voici pour chaque gestionnaire le code crit par le programmeur.

Le code du gestionnaire Quitter1Click


procedure TForm1.Quitter1Click(Sender: TObject); begin Close; //crit par le dveloppeur (fermeture de la fentre) end;

Le code du gestionnaire Ouvrir1Click


procedure TForm1.Ouvrir1Click(Sender: TObject); begin if OpenDialog1.Execute then //crit par le dveloppeur begin Enregistrersous1.enabled:=true; TextEditeur.Lines.LoadFromFile(OpenDialog1.FileName); end end;

Le code du gestionnaire Enregistrersous1Click


procedure TForm1.Enregistrersous1Click(Sender: TObject); begin if SaveDialog1.Execute then // crit par le dveloppeur begin Enregistrersous1.enabled:=false; TextEditeur.Lines.SaveToFile( SaveDialog1.FileName ); end end;

Le code du gestionnaire Couper1Click


procedure TForm1.Couper1Click(Sender: TObject); begin TextEditeur.CutToClipboard; //crit par le dveloppeur end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

591

Le code du gestionnaire Copier1Click


procedure TForm1.Copier1Click(Sender: TObject); begin TextEditeur.CopyToClipboard; //crit par le dveloppeur end;

Le code du gestionnaire Coller1Click


procedure TForm1.Coller1Click(Sender: TObject); begin TextEditeur.PasteFromClipboard; //crit par le dveloppeur end;

Le code du gestionnaire Nouveau1Click


procedure TForm1.Nouveau1Click(Sender: TObject); begin TextEditeur.Clear; &not; crit par le dveloppeur Enregistrersous1.enabled:=true &not; crit par le dveloppeur end; Il est noter que nous avons crit au total 16 lignes de programme Delphi pour construire notre micro-diteur. Ceci est rendu possible par la rutilisabilit de mthodes dj intgres dans les objets de Delphi et en fait prsentes dans le systme Windows. Vous pouvez voir la puissance de ce RAD lorsque vous observez par exemple l'instruction qui a permis de faire excuter le "copier" ou le "chargement d'un fichier" :

TextEditeur.CopyToClipboard;
La mthode CopyToClipboard s'applique l'objet TextEditeur qui est de la classe TMemo; cette instruction correspond un ensemble complexe d'oprations de bas niveau : le TMemo autorise une suite complexe d'oprations permettant de slectionner un texte crit sur plusieurs lignes du TMemo. Il les affiche en surbrillance et la mthode CopyToClipboard rcupre le texte slectionn puis le recopie enfin dans le presse-papier du systme.

TextEditeur.Lines.LoadFromFile(OpenDialog1.FileName);
Nous n'avons par ailleurs eu aucun code particulier crire pour le chargement de fichier texte, la mthode LoadFromFile prsente dans l'objet Lines (de classe TStrings) effectue toutes les actions.

A titre de travail personnel il est recommand d'enrichir ce micro-diteur avec la possibilit de changer la police de caractre, la couleur du fond etc

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

592

Ex-3 Code solution pratique : une pile Lifo avec exception

Cration d'une nouvelle classe


PileVideException = class (Exception) end;

Lancer une PileVideException


procedure ClassLifo.Depiler( var elt : string ) ; begin if not Est_Vide then begin end else raise PileVideException.Create ('Impossible de dpiler: la pile est vide' ) end;

Code complet de la pile


unit ULifoEvent ;

La classe Exception est dans la unit : SysUtils

interface uses classes,Dialogs, SysUtils ; type DelegateLifo = procedure ( Sender: TObject ; s :string ) of object ; PileVideException = class (Exception) end; La classe d'exception personnalise : PileVideException ClassLifo = class (TList) private FOnEmpiler : DelegateLifo ; FOnDepiler : DelegateLifo ; public function Est_Vide : boolean ; procedure Empiler (elt : string ) ; procedure Depiler ( var elt : string ) ; property OnEmpiler : DelegateLifo read FOnEmpiler write FOnEmpiler ; property OnDepiler : DelegateLifo read FOnDepiler write FOnDepiler ; end; ClassUseLifo = class public procedure EmpilerListener( Sender: TObject ; s :string ) ; procedure DepilerListener( Sender: TObject ; s :string ) ; constructor Create ; procedure main ; end; implementation

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

593

procedure ClassLifo.Depiler( var elt : string ) ; begin if not Est_Vide then begin elt :=string (self.First) ; self.Delete(0) ; self.Pack ; self.Capacity := self.Count ; if assigned(FOnDepiler) then FOnDepiler ( self ,elt ) end else raise PileVideException.Create ('Impossible de dpiler: la pile est vide' ) end; Instanciation d'un objet de type : procedure ClassLifo.Empiler(elt : string ) ; PileVideException begin Et lancement de cet objet d'exception. self.Insert(0 , PChar(elt)) ; if assigned(FOnEmpiler) then FOnEmpiler ( self ,elt ) end; function ClassLifo.Est_Vide : boolean ; begin result := self.Count = 0 ; end; { ClassUseLifo } constructor ClassUseLifo.Create ; begin inherited; end; procedure ClassUseLifo.DepilerListener( Sender: TObject ; s :string ) ; begin writeln ( 'On a depile : ' ,s) ; end; procedure ClassUseLifo.EmpilerListener( Sender: TObject ; s :string ) ; begin writeln ( 'On a empile : ' ,s) ; end; procedure ClassUseLifo.main ; var pileLifo : ClassLifo ; ch :string ; begin pileLifo := ClassLifo.Create ; pileLifo.OnEmpiler := EmpilerListener ; pileLifo.OnDepiler := DepilerListener ; pileLifo.Empiler( '[ eau ]' ) ; pileLifo.Empiler( '[ terre ]' ) ; pileLifo.Empiler( '[ mer ]' ) ; pileLifo.Empiler( '[ voiture ]' ) ; writeln ( 'Depilement de la pile :' ) ; while not pileLifo.Est_Vide do begin pileLifo.Depiler(ch) ;

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

594

writeln (ch) ; On tente de dpiler alors que la pile a end; t entirement vide ! writeln ( 'Fin du depilement.' ) ; try pileLifo.Depiler(ch) ; Interception d'un objet Ex de type : writeln (ch) ; PileVideException except on Ex : PileVideException do begin Et gestion de son Message. writeln ( Ex.Message ) ; end; end; readln ; end; end. Application console Project2.dpr instanciant un objet de ClassUseLifo et lanant le test de la pile lifo par invocation de la mthode main.

program Project2; {$APPTYPE CONSOLE} uses SysUtils , UlifoEvent ; var execLifo : ClassUseLifo; excution begin execLifo := ClassUseLifo.Create; execLifo.main end.

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

595

Ex-4 Code solution pratique : liste chane double


unit UDblListChn; interface type TCellDble = class public info:string; constructor Creer(avant,apres:TCellDble;elt:string); procedure InsererAvant(cell:TCellDble); procedure InsererApres(cell:TCellDble); private next:TCellDble; prec:TCellDble; end; TListeDble=class public constructor Create; destructor Liberer; procedure AjouterLeft(elt:string); procedure AjouterRight(elt:string); procedure InsererLeft(rang:integer;elt:string); procedure InsererRight(rang:integer;elt:string); procedure SupprimerLeft(rang:integer); procedure SupprimerRight(rang:integer); function ElementFromLeft(rang:integer):string; function ElementFromRight(rang:integer):string; function IndexFromLeftOf(elt:string):integer; function IndexFromRightOf(elt:string):integer; function Tete:TCellDble; function Fin:TCellDble; function Longueur:integer; procedure Clear; function ParcourirLeft:string; private head,tail:TCellDble; Long:integer; function CellFromLeftAt(rang:integer):TCellDble; function CellFromRightAt(rang:integer):TCellDble; end;

implementation { TCellDble } constructor TCellDble.Crer (avant,apres:TCellDble; elt:string ); begin self.next:=apres; self.prec:=avant; self.info:=elt; end; procedure TCellDble.InsererApres(cell:TCellDble); var cellNext:TCellDble; begin cellNext:= cell.next; self.next:=cellNext; cell.next:=self; cellNext.prec:=self; self.prec:=cell end;

procedure TCellDble.InsererAvant(cell:TCellDble); var cellPrec:TCellDble; begin cellPrec:= cell.prec; self.prec:=cellPrec; cell.prec:=self; cellPrec.next:=self; self.next:=cell end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

596

constructor TListeDble.Create; { TListeDble } begin head:=TCellDble.Crer (nil,nil,'***'); tail:=TCellDble.Crer (nil,nil,'###'); head.next:=tail; tail.prec:=head; Long:=0; end;

function TListeDble.IndexFromRightOf(elt: string): integer; var i,index:integer; L:TCellDble; begin index:=0; L:=self.tail; for i:=1 to long+1 do begin if L.info=elt then destructor TListeDble.Liberer; break begin else self.Clear; begin self.head.Free; L:=L.prec; self.tail.Free; index:=index+1 end; end end; function TListeDble.ElementFromLeft(rang: integer): if index>long then string; index:=0; var L,Loc:TCellDble; result:=index compte:integer; end; begin if (rang<=Long)and(rang>0) then procedure TListeDble.InsererLeft(rang: integer; result:=CellFromLeftAt(rang).info elt: string); var Loc:TCellDble; else result:='?' begin if (rang<=Long)and(rang>0) then end; begin function TListeDble.ElementFromRight(rang: Loc:=TCellDble.Creer(nil,nil,elt); integer): string; Loc.InsererAvant(CellFromLeftAt(rang)); var L,Loc:TCellDble; Long:=Long+1; compte:integer; end begin end; if (rang<=Long)and(rang>0) then result:=CellFromRightAt(rang).info procedure TListeDble.InsererRight(rang: integer; elt: string); else result:='?' var Loc:TCellDble; end; begin if (rang<=Long)and(rang>0) then function TListeDble.IndexFromLeftOf(elt: string): begin integer; Loc:=TCellDble.Creer(nil,nil,elt); var i,index:integer; Loc.InsererApres(CellFromRightAt(rang)); L:TCellDble; Long:=Long+1; begin end index:=0; end; L:=self.head; for i:=1 to long+1 do begin procedure TListeDble.SupprimerLeft(rang: integer); if L.info=elt then var Loc,Lprec,Lnext:TCellDble; break begin if (rang<=Long)and(rang>0) then else begin begin L:=L.next; Loc:=CellFromLeftAt(rang); index:=index+1 Lnext:=Loc.next; Lprec:=Loc.prec; end Lnext.prec:=Lprec; end; if index>long then Lprec.next:=Lnext; index:=0; Loc.Free; result:=index Long:=Long-1 end; end end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

597

procedure TListeDble.SupprimerRight(rang: integer); var Loc,Lprec,Lnext:TCellDble; begin if (rang<=Long)and(rang>0) then begin rang:=long-rang+1; self.SupprimerLeft(rang) end end; function TListeDble.Fin: TCellDble; begin result:=self.tail end; function TListeDble.Tete: TCellDble; begin result:=self.head; end; procedure TListeDble.Clear; var L,Loc:TCellDble; begin if Long>0 then begin L:=self.head; while Assigned(L) do begin Loc:=L; L:=L.next; if (Loc<>head)and(Loc<>tail)then //on n'efface pas la tte et la fin begin Loc.Free ; end end; head.next:=tail; tail.prec:=head; Long:=0; end end; function TListeDble.Longueur: integer; begin result:=Long end; function TListeDble.ParcourirLeft:string; var L:TCellDble; sortie:string; begin L:=self.head; sortie:=''; while Assigned(L) do begin sortie:=sortie+L.info; L:=L.next; end; result:=sortie end;

procedure TListeDble.AjouterLeft(elt: string); var L,Loc:TCellDble; begin L:=self.head; Loc:=TCellDble.Creer(L,L.next,elt); L.next.prec:=Loc; L.next:=Loc; Long:=Long+1; end; procedure TListeDble.AjouterRight(elt: string); var L,Loc:TCellDble; begin L:=self.tail; Loc:=TCellDble.Creer(L.prec,L,elt); L.prec.next:=Loc; L.prec:=Loc; Long:=Long+1; end; function TListeDble.CellFromLeftAt(rang: integer): TCellDble; var L,Loc:TCellDble; compte:integer; begin if (rang<=Long)and(rang>0) then begin L:=self.head; for compte:=1 to rang+1 do begin //la tete compte pour une cellule Loc:=L; L:=L.next; end; result:=Loc end else result:=nil end; function TListeDble.CellFromRightAt(rang: integer): TCellDble; var L,Loc:TCellDble; compte:integer; begin if (rang<=Long)and(rang>0) then begin L:=self.tail; for compte:=1 to rang+1 do begin //la fin compte pour une cellule Loc:=L; L:=L.prec; end; result:=Loc end else result:=nil end; end. // fin unit UDblListChn

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

598

Ex-5 Code solution pratique : hirarchie de quadrilatres


unit UClassQuadrilat; interface uses stdctrls; type cotes=string; angles=string; quadrilatere=class private AB,BC,CD,DA:cotes; public function PropCotes (x:cotes):string; virtual; //--statique car elle sert tous : procedure AfficheCotes (List:TlistBox); procedure AfficheAngles (List:TlistBox); virtual; constructor create; virtual; end; Parallelogramme = class (quadrilatere) private ABC,BCD,CDA,DAB:angles; public function PropCotes(x:cotes):string;override; function PropAngles(x:angles):string; virtual; procedure AfficheAngles(List:TlistBox);override; constructor create;override; end; rectangles = class (parallelogramme) //-- rectangle est dj une function existante en Delphi! public function PropAngles(x:angles):string;override; end; carre = class (rectangles) public function PropCotes(x:cotes):string;override; end;

implementation ///////////////// CLASSE QUADRILATERE //////////////// constructor quadrilatere.create; begin AB:='AB'; BC:='BC'; CD:='CD'; DA:='DA'; end; function quadrilatere.PropCotes(x:cotes):string; begin result:=x+' : quelconque' end; procedure quadrilatere.AfficheCotes(List:TlistBox); begin List.Clear; List.Items.Add(PropCotes(AB)); List.Items.Add(PropCotes(BC)); List.Items.Add(PropCotes(CD)); List.Items.Add(PropCotes(DA)); end; procedure quadrilatere.AfficheAngles(List:TlistBox); begin List.Clear; List.Items.Add('angles quelconques') end;

///////// CLASSE PARALLELOGRAMME //////////// constructor parallelogramme.create; begin inherited; ABC:='ABC'; BCD:='BCD'; CDA:='CDA'; DAB:='DAB'; end; function parallelogramme.PropCotes(x:cotes):string; begin if x='AB' then result:=x+' parallle CD et AB=CD' else if x='BC' then result:=x+' parallle DA et BC=DA' else if x='CD' then result:=x+' parallle AB et CD=AB' else if x='DA' then result:=x+' parallle BC et DA=BC' end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

599

// CLASSE PARALLELOGRAMME (suite) // function parallelogramme.PropAngles (x:angles):string; begin if x='ABC' then result:='ABC = CDA' else if x='BCD' then result:='BCD = DAB' else if x='CDA' then result:='CDA = ABC' else if x='DAB' then result:='DAB = BCD' end; procedure parallelogramme.AfficheAngles (List:TlistBox); begin List.Clear; List.Items.Add(PropAngles(ABC)); List.Items.Add(PropAngles(BCD)); List.Items.Add(PropAngles(CDA)); List.Items.Add(PropAngles(DAB)); end;

//////////////// CLASSE RECTANGLE ////////////////// function rectangles.PropAngles(x:angles):string; var s:string; begin s:=inherited PropAngles(x); result:=s+' = 90' end; //////////////// CLASSE CARRE ////////////////// function carre.PropCotes(x:cotes):string; var s:string; begin s:=inherited PropCotes(x); {celui de paralllogramme: premire classe anctre o il est surcharg ou dfini } if (x='AB') then result:=s+'=BC' else if(x='bc')then result:=s+'=CD' else if(x='cd')then result:=s+'=DA' else if(x='da') then result:=s+'=AB' end; end.

Exemples d'affichages obtenus pour un objet quadrilatre instanci dans chaque type :

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

600

Ex-6 Code solution pratique : un TMemoFlash qui clignote


Une unit d'IHM qui instancie un TmemoFlash lorsque l'on clique sur le bouton Button1 :

unit UClassclickMemo; interface uses StdCtrls,ExtCtrls, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; TMemoFlash=class(TMemo) private Tempo:TTimer; Timing:integer; procedure flashMemo(Sender : TObject); procedure ClickMemo(Sender : TObject); public constructor Create(AOwner: TComponent); destructor Destroy; end; var Form1: TForm1; implementation {$R *.dfm} constructor TMemoFlash.Create(AOwner: TComponent); begin inherited; self.Parent:=TWinControl(AOwner); self.Lines.Append('adresse Owner = '+inttostr((AOwner as TWincontrol).Handle)); self.Lines.Append('adresse Memo = '+inttostr(self.Handle)); Tempo:=TTimer.Create(AOwner);

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

601

Tempo.Enabled:=false; Tempo.Interval:=100; Tempo.OnTimer:= flashMemo; self.OnClick:= ClickMemo; end; destructor TMemoFlash.Destroy; begin Tempo.Free; inherited; end; procedure TMemoFlash.flashMemo(Sender : TObject); begin Timing:=Timing+1; if Timing<10 then if self.color=clyellow then self.color:=claqua else self.color:=clyellow else tempo.enabled:=false end; procedure TMemoFlash.ClickMemo(Sender : TObject); begin Timing:=0; Tempo.Enabled:=true; end; //----------------------------------------------------------------------// procedure TForm1.Button1Click(Sender: TObject); var x:TMemoFlash; begin x:=TMemoFlash.Create(self); end; end.

Ex-7 Code solution pratique : Filtrage avec KeyPress


unit UKeyPress; //permet le filtrage de caractres en mode clavier partir d'un TEdit //(effacement possible seulement la fin du texte entr) interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) EditSaisie: TEdit; MemoApresFiltrage: TMemo; EditFiltre: TEdit; Label1: TLabel; Label2: TLabel;

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

602

Label3: TLabel; procedure EditSaisieKeyPress(Sender: TObject; var Key: Char); procedure EditSaisieClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Dclarations prives } public { Dclarations publiques } LeTexte:string; //contient le texte entr au clavier procedure TexteSansBackSp(var Entree:string;car:char); procedure TexteAvecBackSp(var Entree:string;car:char); end; var Form1: TForm1; implementation {$R *.dfm}

procedure TForm1.TexteSansBackSp(var Entree:string;car:char); //ne traite pas le backspace begin if car<>#13 then begin if car in ['a'..'z']+['A'..'Z'] then begin Entree:=Entree+car; EditFiltre.Text:=Entree end end else begin MemoApresFiltrage.Lines.Add(Entree); Entree:=''; EditSaisie.Text:='' end end; procedure TForm1.TexteAvecBackSp(var Entree:string;car:char); //traitement du backspace partir de la fin du texte begin if (ord(car)=8)and(length(EditSaisie.Text)<>0) then if EditSaisie.Text[length(EditSaisie.Text)] in ['a'..'z']+['A'..'Z'] then begin delete(Entree,length(Entree),1); //on efface le dernier caractre EditFiltre.Text:=Entree //on recopie le nouveau texte end; TexteSansBackSp(Entree,car) end; {----------------------------------------------------------------------------------------} procedure TForm1.EditSaisieKeyPress(Sender: TObject; var Key: Char); //filtrage des lettres non accentues seulement begin TexteSansBackSp(LeTexte,Key); //TexteAvecBackSp(LeTexte,Key); end;

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

603

procedure TForm1.EditSaisieClick(Sender: TObject); begin EditSaisie.SelStart:= length(EditSaisie.text) //replace systmatiquement le curseur la fin end; procedure TForm1.FormCreate(Sender: TObject); begin EditSaisie.SetFocus end; End.

Les bases de linformatique - programmation - ( rv. 04.01.2005 ) EXERCICES

page

604

Vous aimerez peut-être aussi