Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Delphi 10.3
  3. Delphi, le langage Pascal objet
Extrait - Delphi 10.3 Programmation orientée objet en environnement Windows
Extraits du livre
Delphi 10.3 Programmation orientée objet en environnement Windows
9 avis
Revenir à la page d'achat du livre

Delphi, le langage Pascal objet

Introduction

À travers un exemple de programme console DOS, la structure d’un projet Delphi va être expliquée.

Les différents types de variables seront vus et on abordera ensuite quelques fonctions essentielles du langage Delphi héritées pour la plupart du langage Pascal ainsi que les particularités des différents types d’appels entre routines.

Structure des fichiers Delphi

Un projet Delphi se définit par un ensemble de fichiers dont l’extension est figée. Chaque fichier comportant du code source Delphi est aussi appelé unité. Son extension est .pas.

La structure des projets et des fichiers Delphi est simple et facilement manipulable avec ou sans IDE. Ainsi, une brève description reste utile pour tout développeur voulant dupliquer des projets ou des unités car quelques règles sont à respecter.

Il est important de noter que le code source n’est pas case sensitive (indépendant des majuscules ou minuscules) contrairement à la majorité des autres langages comme le C ou le Java.

1. Création d’un projet d’exemple

Pour comprendre cette structure, créons un projet d’exemple.

Via les menus File - New - Console Application, ou en faisant apparaître l’assistant de sélection de projet, le type de projet Console Application apparaît dans la rubrique Delphi.  

images/03EP01.PNG

L’IDE change d’aspect et fait apparaître dans ce cas le fichier .dpr tel quel :

program Project1; 
 
{$APPTYPE CONSOLE} 
 
{$R *.res} 
 
uses 
 System.SysUtils; 
 
begin 
 try 
   { TODO -oUser -cConsole Main : Insérer du code ici } 
 except 
   on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
 end; 
end. 

À partir du gestionnaire de projet, avec un clic droit, il faut choisir Add New - Unit.

images/03EP02.PNG

L’IDE fait apparaître le code de l’unité :

unit Unit1; 
 
interface 
 
implementation 
 
end. 

On remarque que dans le gestionnaire de projet l’unité Unit1.pas est apparue.

images/r03EP03.png

Exécutons File - Save All pour sauvegarder sur le disque le projet en cours dans le répertoire C:\ENI\Chapitre03.

L’IDE nous propose de sauvegarder d’abord l’unité Unit1.pas. Lors de la sauvegarde, renommons-le en UExempleStructure.pas. Après cela, l’IDE propose de sauvegarder le fichier Project1.dproj. De même, nous pouvons le renommer lors de la sauvegarde en DosProject.dproj.

Une fois le processus de sauvegarde achevé, on observe quelques changements dans...

Le mot réservé uses

Le mot réservé uses sert à inclure une unité dans une autre.

Quand une unité UnitA déclare dans ses uses une UnitB, l’unité UnitA peut utiliser tous types, classes, variables, constantes et routines déclarés dans l’interface de l’unité UnitB.

On peut utiliser uses au niveau de la zone interface ou au niveau de la zone implementation.

On essaiera toujours d’inclure une unité au niveau de visibilité le moins élevé, à savoir implementation pour éviter par exemple des références circulaires.

On utilisera le uses dans la zone interface quand un type défini dans l’unité incluse est référencé dans l’interface de l’unité courante.

Les variables et les constantes

1. Déclaration

Une variable est une donnée dont la valeur peut changer au cours du programme, a contrario d’une constante dont la valeur est fixe. En Delphi n’importe quelle entité doit être obligatoirement déclarée.

Une variable se déclare avec le mot réservé var de la manière suivante :

var maVariable : Type; 

Après le mot reservé var, on écrit le nom de la variable maVariable. On définit son type en l’indiquant après un ’:’ qui sert de séparateur entre le nom de la variable et son type. Le caractère ’:’ sert toujours de séparateur pour indiquer un type lors d’une déclaration.

Quand il y a une succession de variables à déclarer, on peut répéter le mot var pour chaque ligne ou bien l’utiliser qu’une seule fois comme si on déclarait une section :

var myVariable1 : Type1; 
var myVariable2 : Type2; 

ou :

var 
    myVariable1 : Type1; 
    myVariable2 : Type2; 

Quand plusieurs variables sont du même type, on peut juxtaposer leur déclaration avec une seule utilisation du mot var comme ci-dessous :

var 
    myVar1,myVar2 : myType; 

Une constante se déclare avec le mot réservé const de la manière suivante :...

Les types de variables Delphi

On peut considérer cinq catégories de données :

  • Les numériques (entier ou décimal)

  • Les booléens

  • Les chaînes de caractères

  • Les descripteurs de fichiers

  • Les autres types plus complexes :

  • énumaration (enum)

  • variant (variant)

  • record (enregistrement)

1. Les types entiers

Voici un tableau résumant l’ensemble des types entiers que l’on peut rencontrer en Delphi :

Type

Intervalle

Format

ShortInt

-128..127

Signé sur 8 bits

SmallInt

-32768..32767

Signé sur 16 bits

FixedInt

-2147483648..2147483647

Signé sur 32 bits

Integer

-2147483648..2147483647

Signé sur 32 bits

Int64

-2^63..2^63-1

Signé sur 64 bits

Byte

0..255

Non signé sur 8 bits

Word

0..65535

Non signé sur 16 bits

FixedUInt

0..4294967295

Non signé sur 32 bits

Cardinal

0..4294967295

Non signé sur 32 bits

UInt64

0..2^64-1

Non signé sur 64 bits

2. Les types décimaux

Voici un tableau résumant l’ensemble des types décimaux que l’on peut rencontrer en Delphi :

Type

Intervalle positif approximatif

Chiffres significatifs

Taille en octets

Real48

2.9e-39 .. 1.7e+38

11-12

6

Single

1.5e-45 .. 3.4e+38

07-08

4

Double

5.0e-324 .. 1.7e+308

15-16

8

Real

5.0e-324 .. 1.7e+308

15-16

8

Extended

Plateformes 32 bits : 3.4e-4932 .. 1.1e+4932

10-20

10

Plateformes 64 bits : 5.0e-324 .. 1.7e+308

15-16

8

Comp

-263+1 .. 263-1

10-20

8

Currency

-922337203685477.5808.. 922337203685477.5807

10-20

8

À noter que le type Extended est plus petit sur un système d’exploitation 64 bits.

3. Les types booléens

Il existe quatre types booléens :

  • Boolean

  • ByteBool

  • WordBool

  • LongBool

Boolean est le type de prédilection. Une variable Boolean occupe 1 octet de mémoire, une variable ByteBool occupe également 1 octet, une variable WordBool occupe 2 octets (un mot), et une variable LongBool occupe 4 octets (deux mots).Les valeurs booléennes sont désignées par les constantes prédéfinies True et False.

4. Les types caractères

On dénombre cinq types caractères en Delphi :

  • Char

  • AnsiChar

  • WideChar

  • UCS2Char 

  • UCS4Char 

Char est équivalent à WideChar, puisque le type de chaîne par défaut est maintenant...

Les opérateurs

Un opérateur est une fonction spéciale dont l’identificateur s’écrit généralement avec des caractères non autorisés pour l’identificateur des fonctions ordinaires. Il s’agit souvent des équivalents aux opérateurs mathématiques pour un langage de programmation.

1. Opérateur d’affectation

L’opération d’affectation se fait par la combinaison :=.

Ainsi, pour affecter la valeur 5 dans la variable dont le nom est myVariableInt, on écrit la ligne suivante :

myVariableInt := 5; 

De même, pour affecter une chaîne de caractères dans la variable myVariableString, on écrit :

myVariableString := 'Hello World'; 

On remarque qu’une chaîne de caractères s’écrit entre deux .

2. Opérations mathématiques

Addition

L’opérateur d’addition est +.

Ainsi, pour affecter le résultat d’une addition, on écrit :

Var  
  myResult : double; 
begin 
 myResult := 8+3.1; 
end; 

ou en utilisant des variables pour les opérandes :

Var 
    Operand1 : integer; 
    Operand2 : double; 
    myResult : double ; 
begin 
 operand1 := 8; 
 operand2 := 3.1; 
 myResult := operand1+operand2; 
end; 

Le type du résultat doit être un double car une des deux opérandes est un nombre décimal.

Et dans les deux cas, la valeur de myResult vaut 11.1.

Dans le cas des chaînes de caractères, l’opérateur + effectue une concaténation des deux chaînes et retourne une nouvelle chaîne de caractères.

var aStringRight,aStringLeft,aStringResult:string; 
begin 
  aStringRight := 'Bonjour !'; 
  aStringLeft := ' Comment allez-vous ?'; 
  aStringResult := aStringRight+ aStringLeft; 
end; 

Dans l’exemple ci-dessus, la valeur de aStringResult vaut ‘Bonjour ! Comment allez-vous ?’. C’est une méthode très pratique pour créer des chaînes de caractères...

Procédures et fonctions

La procédure et les fonctions sont les blocs de code que le développeur écrit à partir des fonctions proposées par le langage de programmation et les composants ou unités que le développeur importe dans son propre projet. On appelle cela des routines.

En Delphi, il existe deux types de routines : les procédures et les fonctions. On déclare une procédure quand aucun résultat n’est retourné par la routine et on doit déclarer une fonction quand un résultat est retourné par le bloc de code.

Le mot réservé pour déclarer une procédure est procedure.

Le mot réservé pour déclarer une fonction est function.

Le fait de déclarer une fonction introduit la variable Result qui sert à retourner le résultat de la routine (voir exemple ci-dessous).

On les définit dans la section interface et on écrit leur implémentation dans la section implementation.

Comme pour les variables, toutes les procédures et les fonctions qui sont définies dans la section interface seront accessibles de manière globale par toutes les autres unités faisant référence à l’unité portant leur implementation.

On peut aussi déclarer les routines au niveau de la section implementation. Elles ne seront pas utilisables par d’autres unités.

On peut même omettre leur déclaration mais lors de leur utilisation, il faut être sûr que leur implémentation est en amont de leur appel.

unit UProcedure; 
 
interface 
 
implementation 
 
function DoSomething():integer; 
begin 
 Result := DoLittleThing(); 
end; 
 
function DoLittleThing():integer; 
begin 
 Result := 5; 
end; 
 
end. 

Cet exemple ne compile pas car la routine DoSomething appelle la routine DoLittleThing et la routine DoLittleThing est ’introuvable’ pour le compilateur. La routine DoLittleThing n’est ni avant la routine DoSomething ni déclarée dans la section interface ou implementation.

Ainsi, les exemples ci-dessous corrigent le problème :

unit UProcedure; 
 
interface 
 
function DoLittleThing():integer; 
 
implementation 
 
function...

Instructions basiques

1. Les tests de conditions

On peut tester des conditions avec deux types de blocs de test : le bloc if then else ou le bloc case of else.

2. If then else

L’instruction if then else est la plus couramment utilisée pour tester une condition logique. Elle s’écrit ainsi :

Begin 
 If (aLogicCondition) then 
 Begin 
    //code to execute if condition is true 
 End 
 Else 
 Begin 
   //code to execute if condition is false 
 End; 
End; 

Après le then et le else, il y a un bloc begin/end pour définir le bloc de code qui s’exécute dans telle ou telle condition.

Dans certains cas, on peut se passer de ce bloc begin/end mais pour une meilleure lisibilité, il est préférable de toujours le définir.

On remarque qu’avant le else, il n’y a pas de ; à la fin du end.

On peut combiner plusieurs évaluations de condition logique avec la combinaison de mot réservé else if comme suit :

Begin 
 If (aLogicCondition) then 
 Begin 
    //code to execute if condition is true 
 End 
 Else If (anotherLogicCondition) then 
 Begin 
    //code to execute if condition is true 
 End 
 Else 
 Begin 
   //code to execute if condition is false 
 End; 
End; 

3. Case of else

On se sert du bloc d’évaluation case of else dans le cas d’énumérations, mais il est équivalent à une succession de if / else if.

On l’écrit comme suit :

  procedure DisplayNameofTheDay(aDayNumber:integer) 
 begin 
     Case aDayNumber of 
         1 : begin 
                //bloc to execute for monday 
                end; 
         2 : begin 
                //bloc to execute for tuesday 
                end; 
         3 : begin 
                 //bloc to execute for wednesday 
           ...

Les directives de compilation conditionnelles

Dans la section Options du projet du chapitre Prise en main de l’IDE de Delphi 10.3, il a été vu qu’on peut configurer des directives de compilation conditionnelles ou conditional defines en anglais. Pour rappel, elles servent à inclure ou exclure des bouts de code selon l’activation ou non de ces directives.

Par exemple, si dans notre application nous avons besoin d’afficher beaucoup d’informations pour des problèmes de mise au point, on pourrait avoir l’implémentation suivante :

procedure ComplexProcedure; 
begin 
  WriteDetailedDebug; 
  DoStep1; 
  WriteDetailedDebug; 
  DoStep2; 
  WriteDetailedDebug; 
end; 
  • Entre chaque étape de la procédure ComplexProcedure, on désire écrire sur la console par exemple des informations de débogage détaillées par l’appel à WriteDetailedDebug.

  • Quand le code est validé, on souhaite que ces informations de débogage n’apparaissent plus quand on livre la version de l’application.

  • Bien sûr, on peut modifier le code pour que la procédure WriteDetailedDebug n’affiche plus rien par une mise en commentaire.

  • Mais pour ne pas modifier le code source, on peut placer WriteDetailedDebug à l’intérieur...

Les fonctions de conversion

Dans le langage pascal, un bon nombre de fonctions de conversion existent. Elles sont listées pour les plus courantes dans la section suivante.

1. Les fonctions de conversion pour les chaînes de caractères

  • IntToStr : convertit un entier (jusqu’à UINT64) en string.

  • FloatToStr : convertit un nombre décimal en string.

  • Val : convertit une chaîne de caractères en nombre entier ou décimal.

  • StrToInt,StrToIntDef : convertit, ou tente de convertir, un string en entier. 

  • StrToFloat,StrToFloatDef : convertit, ou tente de convertir, un string en décimal.

Concernant les deux derniers, il est recommandé d’utiliser les fonctions StrToIntDef ou StrToFloatDef car elles incluent le retour d’une valeur par défaut en cas d’échec de la tentative de conversion.

Ci-dessous est présenté un exemple pour mettre en évidence l’utilisation de ces routines de conversion.

var 
   Astring:string; 
   aValue:integer; 
begin 
 astring:='1234'; 
 aValue := StrToInt(Astring); 
 aString := 'Bonjour'; 
 avalue:= StrToIntDef(Astring,0); 

La première conversion donnera bien sûr 1234 et la deuxième 0 car la chaîne de caractères ’Bonjour’ ne peut pas être convertie en entier. Sans l’utilisation...

Les pointeurs

Les pointeurs sont considérés comme un concept compliqué de la programmation informatique. Les langages récents comme C# et Java masquent complètement cette notion, mais de par la nature même d’un ordinateur, ils sont présents dans tous les langages. Le langage Delphi permet de manipuler beaucoup de concepts en oubliant la notion de pointeur mais cette notion est toujours accessible.

Toute la programmation objet en Delphi utilise les pointeurs sans explicitement y faire référence, ce qui finalement les rend transparents dans ce cas.

Concernant la programmation plus basique que nous voyons dans ce chapitre, il faut explicitement vouloir l’utiliser pour les manipuler.

1. Définition

Considérons que la mémoire d’un ordinateur est un tableau plus ou moins grand où l’on peut stocker des informations. Pour faire simple, imaginons que chaque case de ce tableau représente un octet.

Dans notre programme, nous voulons afficher une image qui fait 80 kilo-octets. Il va falloir adresser 81920 cases (80 x 1024) pour stocker l’image en mémoire. 

Supposons que la première case qui stocke les informations de l’image soit à l’adresse 100000.

Un pointeur sur cette image sera une variable qui contient l’adresse de cette image, soit 100000.

Ainsi, de manière plus générale, un pointeur...