Logo

Marco Cantù

L'essentiel sur Pascal

Traduit de l'anglais par Iannis Papageorgiadis ipapag@village.uunet.be

Chapitre 11

Programme et unités

Les applications Delphi font un usage intensif d'unités, ou modules de programme. Avant l'introduction des classes, les unités constituaient en fait la base de la modularité dans le langage. Dans une application Delphi, chaque fiche est accompagnée de son unité. Lorsqu'on ajoute une nouvelle fiche à un projet (à l'aide du bouton correspondant de la barre d'outils ou à l'aide de la commande Nouvelle fiche du menu Fichier), Delphi ajoute en réalité une nouvelle unité qui définit la classe de la nouvelle fiche.

Les unités

Bien que chaque fiche soit définie dans une unité, le contraire n'est pas vrai. Les unités ne doivent pas définir des fiches; elles peuvent simplement définir et rendre disponibles un ensemble de routines. En sélectionnant la commande Nouveau ... du menu Fichier et ensuite l'icône Unité dans la page Nouveaux éléments du Référentiel d'objets, on peut ajouter une nouvelle unité vide au projet courant. Cette unité vide contient le code suivant qui délimite les sections de l'unité :
unit Unit1;



interface



implementation



end.
Le concept d'unité est simple. Une unité possède un nom unique correspondant à son nom de fichier, une section interface, dans laquelle on déclare ce qui est visible aux autres unités, et une section implementation contenant le code effectif et d'autres déclarations cachées. Enfin, l'unité peut comporter une section facultative initialization avec du code de démarrage qui sera exécuté lors du chargement du programme en mémoire; elle peut également comporter une section facultative finalization qui sera exécutée à l'arrêt du programme.

La structure générale d'une unité, avec toutes ses parties possibles, est la suivante :

unit unitName;



interface

// les autres unités auxquelles on doit faire référence

uses

  A, B, C;

// définition des types exportés

type

  newType = TypeDefinition;
// constantes exportées

const

  Zero = 0;

// variables globales

var

  Total: Integer;

// listes des fonctions et des procédures exportées

procedure MyProc;



implementation



uses

  D, E;

// variables globales cachées

var

  PartialTotal: Integer;

// le code de toutes les fonctions exportées doit être écrit 

procedure MyProc;

begin

  // ... code de la procédure MyProc

end;



initialization

  // partie initialisation facultative


finalization

  // code de nettoyage facultatif

end.
La clause uses au début de la section interface indique à quelles autres unités on doit avoir accès dans la partie interface de l'unité. Y sont comprises les unités qui définissent les types de données auxquels on se réfère dans la définition d'autres types de données, tels que les composants utilisés dans la fiche que l'on est en train de définir.

La seconde clause uses, au début de la section implémentation, indique les unités auxquelles on doit accéder uniquement dans le code de l'implémentation. Si l'on doit se référer à d'autres unités à partir du code des routines et des méthodes, on doit ajouter ces unités à cette seconde clause uses plutôt qu'à la première. Toutes les unités auxquelles on fait référence doivent être présentes dans le répertoire du projet ou dans un répertoire du chemin de recherche (on peut définir le chemin de recherche pour un projet dans la page Répertoires / Conditions de la boîte de dialogue Options de projet de l'option Options... du menu Projet).
 

Les programmeurs C++ doivent savoir que l'instruction uses ne correspond pas à une directive include. L'effet d'une instruction uses est seulement d'importer la portion interface précompilée des unités listées. La portion implémentation de l'unité est considérée uniquement lorsque cette unité est compilée. Les unités auxquelles on se réfère peuvent se trouver soit sous forme de code source (PAS) soit sous forme compilée (DCU), mais la compilation doit avoir été effectuée avec la même version Delphi.
L'interface d'une unité peut déclarer un nombre d'éléments différents, y compris des procédures, des fonctions, des variables globales et des types de données. Dans les applications Delphi, les types de données sont probablement les éléments le plus souvent utilisés. Delphi place automatiquement un nouveau type de données class dans une unité à chaque création d'une fiche. Mais contenir les définitions de fiche n'est certes pas la seule utilisation des unités dans Delphi. On peut encore disposer d'unités traditionnelles, avec fonctions et procédures, et on peut avoir des unités avec des classes qui ne se réfèrent pas à des fiches ou à d'autres éléments visuels.

Unités et portée

En Pascal, les unités sont la clé de l'encapsulation et de la visibilité, et sont probablement encore plus importantes que les mots réservés private et public d'une classe. (En fait, comme on le verra au prochain chapitre, l'effet du mot réservé private est relatif à la portée de l'unité qui contient la classe). La portée d'un identificateur (comme une variable, une procédure, une fonction, ou un type de données) est la portion de code dans lequel l'identificateur est accessible. La règle générale est qu'un identificateur est significatif uniquement à l'intérieur de sa portée -- c'est-à-dire, uniquement dans le bloc dans lequel il est déclaré. On ne peut pas utiliser un identificateur à l'extérieur de sa portée. Voici quelques exemples : Toutes les déclarations dans la partie interface d'une unité sont accessibles à partir de toute partie du programme qui comprend l'unité dans sa clause uses. Les variables des classes fiche sont déclarées de la même façon; on peut ainsi  faire référence à une fiche (et à ses champs publics, méthodes, propriétés et composants) à partir du code de toute autre fiche. Déclarer tout en global est, bien sûr, une pratique de programmation pauvre. En bref, on devrait utiliser le plus petit nombre possible de variables globales.

Unités et homonymie

L'instruction uses constitue la technique standard pour accéder à la portée d'une autre unité. On peut ainsi accéder aux définitions de l'unité. Mais il se pourrait que deux unités auxquelles on se réfère déclarent le même identificateur; ce qui revient à dire qu'on pourrait avoir deux classes ou deux routines portant le même nom.

Dans ce cas, on peut simplement utiliser le nom de l'unité pour préfixer le nom du type ou de la routine définis dans l'unité. On peut, par exemple, faire référence à la procédure ComputeTotal définie dans l'unité Totals en écrivant Totals.ComputeTotal. Cela ne devrait pas souvent être nécessaire, puisqu'on est sérieusement mis en garde contre le fait d'utiliser dans un programme le même nom pour deux objets différents.

Cependant, si on regarde dans la bibliothèque VCL et dans les fichiers Windows, on verra que quelques fonctions Delphi ont le même nom (mais généralement plutôt des paramètres différents) que quelques fonctions API Windows disponibles dans Delphi même. Un exemple est constitué par la simple procédure Beep.

Si on crée un nouveau programme Delphi, on ajoute un bouton et on écrit le code suivant :

procedure TForm1.Button1Click(Sender: TObject);

begin

  Beep;

end;
dès que l'on presse le bouton, on entend un son bref.
Modifions maintenant l'instruction uses de l'unité :
uses

  Windows, Messages, SysUtils, Classes, ...
pour qu'elle prenne cette version fort semblable (déplacer simplement l'unité SysUtils avant l'unité Windows) :
uses

  SysUtils, Windows, Messages, Classes, ...
Si on essaie de recompiler ce code, on obtiendra une erreur de compilation : "Pas assez de paramètres originaux". Le problème provient du fait que Windows définit une autre fonction Beep comportant deux paramètres. Généralement les définitions des premières unités que l'on inclut dans la clause uses sont masquées par les définitions correspondantes des unités indiquées plus loin. La solution sûre et réellement très simple est la suivante:
procedure TForm1.Button1Click(Sender: TObject);

begin

  SysUtils.Beep;

end;
Ce code sera compilé sans se soucier de l'ordre des unités dans les instructions uses. Quelques autres collisions ont lieu dans Delphi pour la simple raison que le code Delphi comporte généralement des méthodes de classes. Avoir deux méthodes avec le même nom dans deux classes différentes ne pose aucun problème. Les problèmes surviennent uniquement avec les routines globales.

Unités et programmes

Une application Delphi est composée de deux sortes de fichiers de code source : une ou plusieurs unités, et un fichier programme. On peut considérer les unités comme des fichiers secondaires auxquels fait référence la partie principale de l'application, le programme. Théoriquement, ceci est vrai. Pratiquement, le fichier programme est un fichier généré automatiquement et il joue un rôle limité. Il sert uniquement à démarrer le programme en faisant tourner la fiche principale. Le code du fichier programme, ou fichier projet Delphi (DPR), peut être constitué soit manuellement, soit en utilisant le Gestionnaire de projet (N.D.T. : menu Voir) et quelques Options de Projet (menu Projet | Options ...) relatives à l'objet application et aux fiches.

La structure du fichier programme est habituellement plus simple que la structure des unités. Voici le code source d'un fichier programme simple :

program Project1;

uses

  Forms,

  Unit1 in ‘Unit1.PAS’ {Form1DateForm};


begin

  Application.Initialize;

  Application.CreateForm (TForm1, Form1);

  Application.Run;

end.
Comme on le voit, il y a simplement une section uses et le code principal de l'application entre les mots réservés begin et end. L'instruction uses du programme est très importante parce qu'elle servira à la gestion de la compilation et à la création des liens de l'application.

Conclusion

Pour le moment du moins, ce chapitre sur la structure d'une application Pascal, écrite en Delphi ou à l'aide d'une des dernières versions de Turbo Pascal, est le dernier de l'ouvrage. Vous pouvez m'envoyer par e-mail vos commentaires et vos questions.

Si après cette introduction au langage Pascal, vous souhaitez approfondir les éléments de l'orienté-objet de Pascal, vous pouvez vous référer à mon livre Mastering Delphi 5 (Sybex, 1999). Vous trouverez plus d'informations sur celui-ci et sur mes autres livres plus avancés (ainsi que sur ceux d'autres auteurs) sur mon site www.marcocantu.com. Le même site héberge des versions mises à jour de ce livre, et ses exemples.

Retour à la première page

© Copyright Marco Cantù, Wintech Italia Srl 1995-99