VII. Types de données avancés de Pascal Objet
Ce chapitre, plutôt théorique, est consacré à la suite de l'étude du langage Pascal Objet. Delphi ne sera utilisé ici que pour vous permettre de manipuler les notions nouvelles.
Les types de données que vous connaissez actuellement, à savoir nombres entiers, à virgule, caractères et chaînes de caractères, énumérés et booléens, suffisent pour de petits programmes, mais deviendront insuffisants dans de nombreuses situations. D'autres types de données plus élaborés devront alors être utilisés. Le début de ce chapitre aborde des types standards de Delphi non encore connus de vous, tandis que la fin du chapitre vous présentera l'une des deux manières pour construire son type personnalisé à partir d'autres types (l'autre manière, nettement plus complexe et puissante, sera vue, mais nettement plus tard, dans le guide).
Les types de données que vous connaissez actuellement, à savoir nombres entiers, à virgule, caractères et chaînes de caractères, énumérés et booléens, suffisent pour de petits programmes, mais deviendront insuffisants dans de nombreuses situations. D'autres types de données plus élaborés devront alors être utilisés. Le début de ce chapitre aborde des types standards de Delphi non encore connus de vous, tandis que la fin du chapitre vous présentera l'une des deux manières pour construire son type personnalisé à partir d'autres types (l'autre manière, nettement plus complexe et puissante, sera vue, mais nettement plus tard, dans le guide).
VII-A. Création de nouveaux types
A partir de ce point, il va vous falloir connaître un nouveau bloc Pascal : le bloc de déclaration de type. Ce bloc permet de définir des nouveaux types, comme les blocs de constantes et de variables définissaient des constantes et des variables.
Un bloc de déclaration de type peut se situer aux mêmes endroits que les blocs const et var. Le bloc commence par contre par le mot Pascal réservé type et possède la syntaxe suivante :
Un bloc de déclaration de type peut se situer aux mêmes endroits que les blocs const et var. Le bloc commence par contre par le mot Pascal réservé type et possède la syntaxe suivante :
|
où Identificateur est un identificateur non encore utilisé qui désignera le nouveau type. Spécification du type peut prendre diverses formes et au fur et à mesure des paragraphes ci-dessous, nous en verrons un certain nombre. Une habitude veut que tous les identificateurs de types personnalisés commencent par la lettre T majuscule suivi d'un nom descriptif (toutefois, les types pointeurs que nous étudierons au chapitre 9 font exception à cette convention en utilisant la lettre P).
Il est possible de donner pour Spécification du type un type standard, tel 'integer' ou 'byte', ou n'importe quel type connu.
Les types ainsi définis peuvent être utilisés ensuite dans les blocs const et var de la manière suivante :
Il est possible de donner pour Spécification du type un type standard, tel 'integer' ou 'byte', ou n'importe quel type connu.
Les types ainsi définis peuvent être utilisés ensuite dans les blocs const et var de la manière suivante :
|
Ces types peuvent également être utilisés partout où un type est requis, par exemple dans la liste des paramètres d'une procédure ou d'une fonction ou comme type de résultat d'une fonction. Voici un exemple :
|
(UpperCase est une fonction fournie par Delphi qui renvoie la chaine donnée en paramètre convertie en majuscules)
Exercice 1 : (voir la solution)
Ecrivez le bloc type complet déclarant les deux nouveaux types suivants :
Ecrivez le bloc type complet déclarant les deux nouveaux types suivants :
- TChaine200 : type chaîne de 200 caractères.
- TEntier : type équivalent au type integer.
VII-B. Type ordinaux
Les types ordinaux sont non pas un nouveau type mais une particularité pour un type. Certains types permettent des valeurs classées suivant un ordre. Ces types sont alors dits ordinaux. C'est le cas, parmi les types que vous connaissez, de tous les types entiers ('integer', 'byte', ...), des booléens, des caractères (mais pas des chaînes de caractères) et des énumérés. Il sera dorénavant mentionné lors de la présentation de nouveaux types s'ils sont ordinaux ou pas.
Les types ordinaux ont tous une sorte de correspondance avec les nombres entiers. Chaque donnée (constante ou variable) d'un type ordinal possède ce qu'on appelle une valeur ordinale, qui est donnée par la fonction 'Ord'. Cette fonction fait partie d'un ensemble de fonctions assez particulières qui acceptent des paramètres divers. En l'occurence, 'Ord' accepte n'importe quelle constante ou variable de type ordinal.
La fonction 'Ord' sera utilisée dans les paragraphes suivants, de même que nous reviendrons sur les types ordinaux.
Les types ordinaux ont tous une sorte de correspondance avec les nombres entiers. Chaque donnée (constante ou variable) d'un type ordinal possède ce qu'on appelle une valeur ordinale, qui est donnée par la fonction 'Ord'. Cette fonction fait partie d'un ensemble de fonctions assez particulières qui acceptent des paramètres divers. En l'occurence, 'Ord' accepte n'importe quelle constante ou variable de type ordinal.
La fonction 'Ord' sera utilisée dans les paragraphes suivants, de même que nous reviendrons sur les types ordinaux.
VII-C. Type intervalle
Le type intervalle permet de définir un nouveau type ordinal personnalisé autorisant un intervalle de valeurs ordinales, en donnant les valeurs extrèmales (son minimum et son maximum). Ceci permettra de nombreuses choses notamment pour un autre type que nous allons bientôt voir.
Ce type s'écrit comme suit :
ValeurMinimale..ValeurMaximale
Où ValeurMinimale et ValeurMaximale sont du même type ordinal. Il est à noter que la valeur ordinale de ValeurMinimale doit être inférieure ou égale à celle de ValeurMaximale, ou sinon le compilateur signalera une erreur. La déclaration d'un type, ou d'une variable de ce type, se font de la manière suivante :
Ce type s'écrit comme suit :
ValeurMinimale..ValeurMaximale
Où ValeurMinimale et ValeurMaximale sont du même type ordinal. Il est à noter que la valeur ordinale de ValeurMinimale doit être inférieure ou égale à celle de ValeurMaximale, ou sinon le compilateur signalera une erreur. La déclaration d'un type, ou d'une variable de ce type, se font de la manière suivante :
|
Exemples :
|
Déclarer une constante de type intervalle avec une valeur hors de cet intervalle est interdit. De même, pour des variables de type intervalle, assigner directement une valeur hors de l'intervalle est interdit par le compilateur :
|
provoquera une erreur, mais par contre :
|
sera accepté et pourtant "Chiffre" n'est plus entre les deux valeurs extremales. Ce sera à vous de faire attention.
VII-D. Compléments sur les types énumérés
Il est possible de déclarer de nouveaux types énumérés, personnalisés. La syntaxe en est la suivante :
Nom_du_type = (IdValeur0, IdValeur1, ..., IdValeurn);
où Nom_du_type, IdValeur0, IdValeur1, ..., IdValeurn sont des identificateurs non utilisés. Nom_du_type désignera alors le type et IdValeur0, IdValeur1, ..., IdValeurn seront les n+1 valeurs possibles d'une constante ou variable de ce type. Chacun de ces identificateur a une valeur ordinale (qu'on obtient, je rappelle, à l'aide de la fonction Ord) déterminée par la déclaration du type : le premier identificateur prend la valeur ordinale 0, le suivant 1, et ainsi de suite. IdValeur0 a donc pour valeur 0, IdValeur1 a pour valeur 1, IdValeurn a pour valeur n. Par convention, on essayera de nommer IdValeurx par deux ou trois lettres minuscules qui sont une abréviation du nom de type, puis par une expression significative.
Nom_du_type = (IdValeur0, IdValeur1, ..., IdValeurn);
où Nom_du_type, IdValeur0, IdValeur1, ..., IdValeurn sont des identificateurs non utilisés. Nom_du_type désignera alors le type et IdValeur0, IdValeur1, ..., IdValeurn seront les n+1 valeurs possibles d'une constante ou variable de ce type. Chacun de ces identificateur a une valeur ordinale (qu'on obtient, je rappelle, à l'aide de la fonction Ord) déterminée par la déclaration du type : le premier identificateur prend la valeur ordinale 0, le suivant 1, et ainsi de suite. IdValeur0 a donc pour valeur 0, IdValeur1 a pour valeur 1, IdValeurn a pour valeur n. Par convention, on essayera de nommer IdValeurx par deux ou trois lettres minuscules qui sont une abréviation du nom de type, puis par une expression significative.
Note aux programmeurs en C, C++ ou autres : Delphi n'offre pas les mêmes possibilités que le C ou le C++ en ce qui concerne les énumérations : il n'est en effet pas possible de donner des valeurs personnalisées aux identificateurs constituant la déclaration du type. Il sera cependant possible d'outrepasser cette limitation en déclarant une constante du type énuméré et en utilisant la syntaxe (qui effectue un transtypage) : Nom_De_Type_Enumere(valeur_ordinale) On n'a que rarement besoin d'un tel assemblage, contactez-moi donc si vous avez besoin de précisions. |
Sous Delphi, retournez au code source de la procédure TForm1.Button1Click. Remplacez son contenu par l'exemple ci-dessous :
|
Cet exemple déclare un nouveau type énuméré local à la procédure (mais il pourrait aussi bien être déclaré ailleurs) nommé 'TTypeSupport'. Une variable 'Supp1' est déclarée de ce type. Les valeurs possibles pour cette variable sont donc tsDisq35, tsDisqueDur, tsCDRom, tsDVDRom et tsZIP. Ces identificateurs ont une valeur ordinale. Pour vous la faire voir, une valeur a été donnée à la variable (vous pouvez changer cette valeur en piochant dans les valeurs possibles mais si vous tentez de mettre autre chose qu'une de ces valeurs, le compilateur signalera une erreur). La valeur de la variable est alors transmise à la fonction Ord qui renvoie un nombre entier positif. On a choisi de stocker ce résultat dans une variable I de type 'byte' mais on aurait pu choisir 'integer' (il y a moins de 256 valeurs possibles pour le type 'TTypeSupport', donc le type 'byte' convient bien avec sa limite de 255). Après l'exécution de l'instruction, on affiche la valeur de I à l'aide de ShowMessage et de IntToStr (IntToStr fonctionne comme FloatToStr, mais uniquement avec les nombres entiers, il sera préférable de l'utiliser avec ces derniers, plutôt que d'utiliser partout FloatToStr). En lançant l'application, vous verrez donc s'afficher la valeur ordinale de 'tsCDRom', soit 2.
C'est l'occasion idéale pour vous parler de 2 fonctions et de 2 procédures assez particulières : high, low, inc, dec. Elles acceptent chacune un unique paramètre qui doit être ordinal.
C'est l'occasion idéale pour vous parler de 2 fonctions et de 2 procédures assez particulières : high, low, inc, dec. Elles acceptent chacune un unique paramètre qui doit être ordinal.
- 'High' (c'est une fonction), tout comme 'Low' a une particularité : son paramètre peut être soit une variable de type ordinal, ou directement le nom d'un type ordinal. 'High' renvoie toujours une valeur (et non un type) du même type que le paramètre transmis (le type de la variable si le paramètre est une variable ou du type donné en paramètre si le paramètre est un type), qui est la valeur dont la valeur ordinale est la plus importante pour ce type. Par exemple, 'High(TTypeSupport)' vaudra 'tsZIP'.
- 'Low' (c'est une fonction) fonctionne de la même manière, mais renvoie la valeur dont la valeur ordinale est la plus faible. Ainsi, par exemple, 'Low(TTypeSupport)' vaudra 'tsDisq35'.
- 'Inc' (c'est une procédure) accepte n'importe quelle variable de type ordinal, et la modifie en augmentant sa valeur ordinale d'une unité. Ainsi, pour un nombre entier, 'Inc' a le même effet que si l'on additionnait 1. Par contre, sur les autres types, les effets sont plus intéressants car on ne peut pas leur ajouter 1 directement, il faut passer par 'Inc'.
- 'Dec' a l'effet contraire : il enlève 1 à la valeur ordinale de la variable qu'on lui transmet en paramètre.
Exemple :
|
Dans l'exemple ci-dessus, la valeur de la variable 'Supp1' est fixée à la valeur de valeur ordinale la plus faible du type 'TTypeSupport', qui est donc 'tsDisq35'. Un appel à 'ShowMessage' permet ensuite d'afficher la valeur ordinale de Supp1. Vous remarquez que nous avons grimpé d'un échelon en n'utilisant plus de variable I, mais directement la valeur qui lui était affectée.
La variable 'Supp1' est ensuite transmise à 'Inc', qui augmente sa valeur ordinale de 1. Supp1 vaut donc 'tsDisqueDur'. Pour nous en assurer, on affiche à nouveau la valeur ordinale de 'Supp1'. Le même procédé est enfin appliqué pour tester la procédure 'Dec'.
Si vous voulez voir la chose en application, entrez le code source ci-dessus dans Delphi (on se sert encore et toujours de la procédure 'TForm1.Button1Click', et lancez l'application.
La variable 'Supp1' est ensuite transmise à 'Inc', qui augmente sa valeur ordinale de 1. Supp1 vaut donc 'tsDisqueDur'. Pour nous en assurer, on affiche à nouveau la valeur ordinale de 'Supp1'. Le même procédé est enfin appliqué pour tester la procédure 'Dec'.
Si vous voulez voir la chose en application, entrez le code source ci-dessus dans Delphi (on se sert encore et toujours de la procédure 'TForm1.Button1Click', et lancez l'application.
Exercice 2 : (voir la solution)
Ecrivez un type énuméré pour les 7 jours de la semaine. Déclarez une variable de ce type, initialisez-la à une valeur de votre choix et affichez sa valeur ordinale (utilisez la procédure habituelle pour cela).
Si vous le pouvez, essayez de ne pas utiliser de variable intermédiaire comme dans l'exemple ci-dessus.
Ecrivez un type énuméré pour les 7 jours de la semaine. Déclarez une variable de ce type, initialisez-la à une valeur de votre choix et affichez sa valeur ordinale (utilisez la procédure habituelle pour cela).
Si vous le pouvez, essayez de ne pas utiliser de variable intermédiaire comme dans l'exemple ci-dessus.
VII-E. Type ensemble
Le type ensemble permet de créer des ensembles à cardinal fini (le cardinal d'un ensemble est le nombre d'éléments dans cet ensemble). Les ensembles en Pascal ne peuvent contenir que des constantes de type ordinal, dont la valeur ordinale est comprise entre 0 et 255. Toutes les constantes entières entre 0 et 255 conviennent donc, ainsi que les caractères et la plupart des types énumérés. On ne peut cependant pas mélanger les types à l'intérieur d'un ensemble, le type des éléments étant décidé dans la déclaration du type.
Le type ensemble s'écrit :
set of type_ordinal;
où type_ordinal désigne au choix un nom de type ordinal ou spécifie directement un type ordinal. Voici des exemples :
Le type ensemble s'écrit :
set of type_ordinal;
où type_ordinal désigne au choix un nom de type ordinal ou spécifie directement un type ordinal. Voici des exemples :
|
Dans l'exemple ci-dessus, 'TResultats' pourra contenir des entiers de type 'byte', 'TNotes' pourra contenir des entiers entre 0 et 20, et 'TSupports' pourra contenir des éléments de type 'TTypeSupport'.
Il est alors possible de déclarer des variables de ces types. Pour utiliser ces variables, vous devez savoir comment on écrit un ensemble en Pascal : il se note entre crochets et ses éventuels sous-éléments sont notés entre virgules. J'ai bien dit éventuel car l'ensemble vide est autorisé. Par sous-élément, on entend soit un élément simple, soit un intervalle (rappelez-vous des types intervalles). les exemples ci-dessous sont des ensembles.
Il est alors possible de déclarer des variables de ces types. Pour utiliser ces variables, vous devez savoir comment on écrit un ensemble en Pascal : il se note entre crochets et ses éventuels sous-éléments sont notés entre virgules. J'ai bien dit éventuel car l'ensemble vide est autorisé. Par sous-élément, on entend soit un élément simple, soit un intervalle (rappelez-vous des types intervalles). les exemples ci-dessous sont des ensembles.
|
Il est en outre possible de manipuler ces ensembles comme les ensembles manipulés en mathématiques : union, intersection sont possible, de même que le retrait d'un élément (si jamais vous ne maîtrisez pas ces notions, adressez-vous au professeur de mathématiques le plus proche, ou à moi).
|
Il est également possible de comparer deux ensembles. Pour cela, on utilise des opérateurs de comparaison, comme ceux que vous connaissez déjà. Le résultat de l'opérateur est alors un booléen (vous apprendrez assez rapidement quoi faire de ce genre de booléens, qui pour le moment, il est vrai, sont assez inutilisables, mis à part dans des affectations). ci-dessous, A et B désignent deux ensembles de même type, x est un élément acceptable dans ces ensembles.
|
Il est également possible de déclarer des constantes de type ensemble. Voici un exemple :
|
Pour terminer ce point, voici un certainement très utile exemple général : Pour terminer ce point, voici un certainement très utile exemple général :
|
Cet exemple déclare les types 'TTypeSupport' et 'TSupports', une variable de type ensemble et une constante de type ensemble. La première instruction permet de donner à la variable une valeur de départ, on appelle cela une initialisation. Nous aurons l'occasion d'en reparler. La deuxième instruction permet de retirer un élément et d'en ajouter un autre. Notez que cela a été fait en une seule instruction, car les opérateurs sont exécutés de gauche à droite, sauf si des parenthèses sont présentes.
VII-F. Tableaux
Les tableaux sont une possibilité puissante du langage Pascal. Imaginons par exemple que vous vouliez stocker 100 nombres entiers de type 'word'. Vous pourriez déclarer (très mauvaise méthode) 100 variables de type 'word'. Une solution préfèrable sera d'utiliser un tableau. Le principe d'un tableau est de regrouper un certain nombre d'élements du même type, en ne déclarant qu'une variable ou qu'une constante. Les éléments individuels sont ensuite accessibles via un ou plusieurs indices de position dans le tableau.
Les tableaux en Pascal peuvent avoir une ou plusieurs dimensions. Nous consacrerons un paragraphe à l'étude de chaque cas. Un troisième paragraphe présentera des notions avancées permettant de dépasser le cadre des tableaux standards vus dans les deux premiers paragraphes. Un dernier paragraphe présentera les tableaux de taille dynamique, utilisables à partir de Delphi 4.
Les tableaux en Pascal peuvent avoir une ou plusieurs dimensions. Nous consacrerons un paragraphe à l'étude de chaque cas. Un troisième paragraphe présentera des notions avancées permettant de dépasser le cadre des tableaux standards vus dans les deux premiers paragraphes. Un dernier paragraphe présentera les tableaux de taille dynamique, utilisables à partir de Delphi 4.
VII-F-1. Tableaux à une seule dimension
Un tableau à une seule dimension se déclare de la façon suivante :
array[intervalle] of type;
où array définit un tableau. les crochets entourent les données de dimension du tableau. Pour un tableau à une seule dimension, un seul paramètre est donné, de type intervalle (il est possible d'utiliser d'autres choses que les intervalles, ceci sera vu dans le § VII-F-3). Vient ensuite le mot réservé of qui est suivi du type des éléments du tableau. Cet élément est un type. Tous les types vus jusqu'à présent sont acceptés, y compris d'autres tableaux. Il faudra cependant, pour certains types comme les ensembles, déclarer d'abord un type ensemble, puis utiliser ce nom de type pour déclarer le tableau. En principe, tous les types sont autorisés, du moment que la taille du tableau reste en dessous d'une limite dépendant de la version de Delphi.
Il est possible de déclarer des types, des variables et des constantes de type tableau (c.f. exemple ci-dessous). Pour accèder à un tableau, il suffit de donner le nom de la variable tableau de la constante tableau. Pour accèder à un élément, on donne le nom du tableau suivi de l'indice entre crochets. Voyez l'exemple ci-dessous pour mieux comprendre :
array[intervalle] of type;
où array définit un tableau. les crochets entourent les données de dimension du tableau. Pour un tableau à une seule dimension, un seul paramètre est donné, de type intervalle (il est possible d'utiliser d'autres choses que les intervalles, ceci sera vu dans le § VII-F-3). Vient ensuite le mot réservé of qui est suivi du type des éléments du tableau. Cet élément est un type. Tous les types vus jusqu'à présent sont acceptés, y compris d'autres tableaux. Il faudra cependant, pour certains types comme les ensembles, déclarer d'abord un type ensemble, puis utiliser ce nom de type pour déclarer le tableau. En principe, tous les types sont autorisés, du moment que la taille du tableau reste en dessous d'une limite dépendant de la version de Delphi.
Il est possible de déclarer des types, des variables et des constantes de type tableau (c.f. exemple ci-dessous). Pour accèder à un tableau, il suffit de donner le nom de la variable tableau de la constante tableau. Pour accèder à un élément, on donne le nom du tableau suivi de l'indice entre crochets. Voyez l'exemple ci-dessous pour mieux comprendre :
|
Vous remarquerez dans l'exemple ci-dessus que 'Nombres' est un tableau d'entiers positifs. On peut donc affecter à chaque élément (on dira également chaque case, ou cellule) un entier positif. La deuxième variable est un tableau d'éléments de type TTypeSupport. Un tel tableau pourrait être utilisé pour stocker les types de lecteur de A à Z sur un ordinateur. Chaque case du tableau contient un élément de type TTypeSupport. On affecte des valeurs à 3 de ces cases.
La constante devrait retenir votre attention : pour donner la valeur d'une constante de type tableau, on donne une liste de tous les éléments, dans l'ordre, séparés par des virgules, le tout entre parenthèses. Ici, les éléments sont des chaînes de caractères et le tableau en contient 3 numérotées de 0 à 2.
La constante devrait retenir votre attention : pour donner la valeur d'une constante de type tableau, on donne une liste de tous les éléments, dans l'ordre, séparés par des virgules, le tout entre parenthèses. Ici, les éléments sont des chaînes de caractères et le tableau en contient 3 numérotées de 0 à 2.
Exercice 3 : (voir la solution)
Dans la procédure habituelle, déclarez un type tableau de dix chaînes de caractères, indicées de 1 à 10. Déclarez une variable de ce type et initialisez une de ses cases à la chaîne : « Bonjour ». Affichez ensuite le contenu de cette case à l'aide de ShowMessage (Pour cette fois, vous avez le droit d'utiliser une variable temporaire, essayez cependant de vous en passer).
Dans la procédure habituelle, déclarez un type tableau de dix chaînes de caractères, indicées de 1 à 10. Déclarez une variable de ce type et initialisez une de ses cases à la chaîne : « Bonjour ». Affichez ensuite le contenu de cette case à l'aide de ShowMessage (Pour cette fois, vous avez le droit d'utiliser une variable temporaire, essayez cependant de vous en passer).
VII-F-2. Tableaux à plusieurs dimensions
Vous aurez parfois besoin de tableaux à plusieurs dimensions (les tableaux à 2 dimensions sont similaires aux tableaux à double entrée que vous connaissez certainement déjà par exemple dans Microsoft Word, mais Pascal permet d'avoir plus de 2 dimensions). Je ne vous donnerai pas de preuve de leur utilité, vous en connaissez certainement déjà. Un tableau multidimensionnel se déclare ainsi :
array[intervalle1, intervalle2, ...] of type;
où intervalle1 est la première dimension du tableau, intervalle2 la deuxième, ... et type est encore le type des éléments stockés dans le tableau.
Les types, variables et constantes se déclarent en utilisant cette syntaxe. Pour donner des valeurs aux éléments d'une variable tableau, on utilise la syntaxe suivante :
nom_du_tableau[indice1, indice2, ...] := valeur;
où nom_du_tableau est le nom d'une variable de type tableau, indice1 est l'indice dans la première dimension, indice2 dans la deuxième, ... et valeur la valeur (dont le type est donné dans la déclaration du tableau) à stocker dans cette case.
Pour fixer la valeur d'une constante de type tableau multidimensionnel, c'est un peu plus compliqué. Considérons un tableau de dimension 3 : on devra faire comme si c'était en fait un tableau à 1 dimension dont chaque case contient un tableau à 1 dimension, qui lui-même est de dimension 1. Voyez l'exemple ci-dessous qui récapitule tout ce que nous venons de dire (Attention, la première instruction, à savoir l'affectation d'un tableau à une variable tableau, est possible à partir de Delphi 4 seulement, si vous n'avez que Delphi 2 ou 3, il vous faudra attendre que nous ayons vu les boucles 'for' pour passer outre ce genre de difficulté).
array[intervalle1, intervalle2, ...] of type;
où intervalle1 est la première dimension du tableau, intervalle2 la deuxième, ... et type est encore le type des éléments stockés dans le tableau.
Les types, variables et constantes se déclarent en utilisant cette syntaxe. Pour donner des valeurs aux éléments d'une variable tableau, on utilise la syntaxe suivante :
nom_du_tableau[indice1, indice2, ...] := valeur;
où nom_du_tableau est le nom d'une variable de type tableau, indice1 est l'indice dans la première dimension, indice2 dans la deuxième, ... et valeur la valeur (dont le type est donné dans la déclaration du tableau) à stocker dans cette case.
Pour fixer la valeur d'une constante de type tableau multidimensionnel, c'est un peu plus compliqué. Considérons un tableau de dimension 3 : on devra faire comme si c'était en fait un tableau à 1 dimension dont chaque case contient un tableau à 1 dimension, qui lui-même est de dimension 1. Voyez l'exemple ci-dessous qui récapitule tout ce que nous venons de dire (Attention, la première instruction, à savoir l'affectation d'un tableau à une variable tableau, est possible à partir de Delphi 4 seulement, si vous n'avez que Delphi 2 ou 3, il vous faudra attendre que nous ayons vu les boucles 'for' pour passer outre ce genre de difficulté).
|
Dans l'exemple ci-dessus, un type de tableau à 3 dimensions a été créé, ce type étant ensuite utilisé pour déclarer une constante et une variable. Attardez-vous sur la constante 'TabExemple' : sa valeur est donnée entre parenthèses. Chaque élément de la première dimension est considéré comme un tableau, et est donc encore noté entre parenthèses. Enfin, chaque élément de la deuxième dimension est considéré comme un tableau de 2 éléments, dont vous connaissez déjà la déclaration. Il est assez facile de se tromper dans les déclarations de constantes de type tableau, mais rassurez-vous, le compilateur saura vous signaler toute parenthèse mal placée lors de la compilation du projet.
La première instruction permet d'initialiser la variable : on lui donne une valeur. En effet, contrairement à certains langages que vous connaissez peut-être, la mémoire utilisée par les variables n'est pas nettoyée avant utilisation, c'est-à-dire que les variables, avant que vous leur donniez une première valeur, peuvent valoir tout et n'importe quoi (en général, c'est surtout n'importe quoi !). Une initialisation permet de donner une première valeur à une variable. Il ne faudra jamais utiliser la valeur d'une variable sans qu'elle ait été initialisée auparavant.
On affecte directement la valeur d'une constante de type TTab3Dim à une variable de même type, il n'y a donc pas de problème.
La deuxième instruction modifie la valeur d'une des cases du tableau, repèrez bien les indices et reportez-vous à la déclaration de la constante pour voir à quelle position ces indices font référence. Il vous faudra tenir compte des intervalles dans lesquels sont pris les indices (les indices de dimension 3 sont pris dans l'intervalle 0..1).
La première instruction permet d'initialiser la variable : on lui donne une valeur. En effet, contrairement à certains langages que vous connaissez peut-être, la mémoire utilisée par les variables n'est pas nettoyée avant utilisation, c'est-à-dire que les variables, avant que vous leur donniez une première valeur, peuvent valoir tout et n'importe quoi (en général, c'est surtout n'importe quoi !). Une initialisation permet de donner une première valeur à une variable. Il ne faudra jamais utiliser la valeur d'une variable sans qu'elle ait été initialisée auparavant.
On affecte directement la valeur d'une constante de type TTab3Dim à une variable de même type, il n'y a donc pas de problème.
La deuxième instruction modifie la valeur d'une des cases du tableau, repèrez bien les indices et reportez-vous à la déclaration de la constante pour voir à quelle position ces indices font référence. Il vous faudra tenir compte des intervalles dans lesquels sont pris les indices (les indices de dimension 3 sont pris dans l'intervalle 0..1).
VII-F-3. Notions avancées sur les tableaux
Nous nous sommes limités jusqu'à présent pour les indices des tableaux à des intervalles. Ce n'est que l'une des possibilités offertes : la plus simple. Il est en fait possible d'utiliser tout type ordinal en tant qu'indice. Le cas le plus intéressant à examiner est celui des types énumérés : il sera possible de déclarer un tableau tel que celui-ci :
array[tsDisqueDur..tsDVDRom] of Char;
Mais il sera encore plus intéressant d'utiliser des noms de types énumérés en guise d'indices. Ainsi, la déclaration suivante permet d'utiliser un tableau dont chaque case est une valeur de type TTypeSupport :
type TTabSupport = array[TTypeSupport] of string;
Ce nouveau type pourra se révèler très utile, pour vous en rendre compte, regardez le code source suivant :
array[tsDisqueDur..tsDVDRom] of Char;
Mais il sera encore plus intéressant d'utiliser des noms de types énumérés en guise d'indices. Ainsi, la déclaration suivante permet d'utiliser un tableau dont chaque case est une valeur de type TTypeSupport :
type TTabSupport = array[TTypeSupport] of string;
Ce nouveau type pourra se révèler très utile, pour vous en rendre compte, regardez le code source suivant :
|
Le premier type est désormais habituel. Le deuxième déclare un tableau dont les cases sont indexées par des valeurs de type TTypeSupport et dont les cases contiennent des chaînes de caractères. Vient ensuite une déclaration de constante tableau. Celle-ci s'écrit en précisant d'abord le type de la constante précédé de deux points (:), puis en donnant la valeur de la constante après un signe =. La valeur s'écrit entre parenthèses : une liste de valeurs est donnée, et affectée aux cases dans l'ordre. Les valeurs sont séparées par des virgules. Chaque chaîne correspond à un élément de type TTypeSupport.
Les deux variables serviront dans les instructions.
La première de ces instructions initialise Sup1. La deuxième initialise msg, en utilisant la constante de type tableau. Comme les indices sont de type TTypeSupport, on transmet une valeur de type TTypeSupport en indice, en l'occurence c'est la valeur de 'Sup1' qui est utilisée. Chaque case du tableau étant une chaîne de caractères, NomDesSupports[Sup1] est une chaîne, qui est affectée à une variable de type chaîne. La dernière instruction est déjà connue de vous puisqu'elle se contente d'afficher un message contenant la valeur de 'msg'.
Lorsque vous exécutez l'application, un clic sur le bouton affiche alors la boite de dialogue ci-dessous :
Les deux variables serviront dans les instructions.
La première de ces instructions initialise Sup1. La deuxième initialise msg, en utilisant la constante de type tableau. Comme les indices sont de type TTypeSupport, on transmet une valeur de type TTypeSupport en indice, en l'occurence c'est la valeur de 'Sup1' qui est utilisée. Chaque case du tableau étant une chaîne de caractères, NomDesSupports[Sup1] est une chaîne, qui est affectée à une variable de type chaîne. La dernière instruction est déjà connue de vous puisqu'elle se contente d'afficher un message contenant la valeur de 'msg'.
Lorsque vous exécutez l'application, un clic sur le bouton affiche alors la boite de dialogue ci-dessous :
Essayez de remplacer la valeur de départ de 'Sup1' par une autre valeur de type 'TTypeSupport' dans la première instruction. Ceci aura un effet sur la valeur de 'msg', et modifiera donc le message affiché.
Exercice 4 : (voir la solution)
- Reprenez le code source de l' exercice 2. Déclarez une constante de type tableau avec comme indices le type TJourSemaine, et comme contenu des cases, des chaînes de caractères. Le contenu de chaque case sera une chaîne donnant le nom du jour représenté par la valeur de type TJourSemaine indicant cette case ('Lundi' pour jsLundi par exemple).
- Dans le code source, au lieu d'afficher la valeur ordinale de la variable de type TJourSemaine, affichez à la place le nom du jour correspondant à la valeur de cette variable en utilisant la constante déclarée à la question 1 (indication : utilisez la valeur de la variable comme indice de la constante tableau et affichez la case ainsi obtenue).
VII-F-4. Tableaux de taille dynamique
Attention : Les tableaux de taille dynamique sont utilisables à partir de Delphi 4. Si vous avez une version antérieure, rien ne vous empèche de lire ce paragraphe, mais les manipulations seront impossibles. Sachez également que les tableaux de taille dynamique ne sont pas exactement ce qu'ils semblent être, car ils sont liés à la notion de pointeurs vue plus loin dans le guide. Soyez prudents dans l'utilisation de ces tableaux tant que vous n'aurez pas lu la section consacrée aux pointeurs. |
Le langage Pascal Objet est en constante évolution dans les versions successives de Delphi. Depuis la version 5, il est possible de créer des tableaux de taille dynamique, c'est-à-dire dont la taille n'est pas fixée au départ une fois pour toutes. Ces nouveaux tableaux sont toujours indexés par des entiers, et à partir de 0. Les tableaux de taille dynamique multidimensionnels, bien qu'un peu plus délicats à manipuler, sont toutefois possibles.
Un tableau dynamique à une dimension est de la forme :
array of type_de_base
où type_de_base, comme pour les tableaux non dynamiques, est le type des éléments stockés dans le tableau. Vous remarquez que la partie qui donnait auparavant les dimensions, les bornes et les limites du tableau (la partie entre crochets) est justement absente pour les tableaux dynamiques.
Ces derniers tableaux sont plus complexes à manipuler que les tableaux standards : déclarer une variable de type tableau dynamique ne suffit pas, comme dans la plupart des autres cas de variables, pour que la variable soit utilisable. Du fait que leur taille n'est pas fixe, il faudra la gèrer en même temps que le tableau lui-même et donc fixer le nombre d'éléments avant la première utilisation du tableau au moyen d'une procédure : 'SetLength'. 'SetLength' accepte plusieurs paramètres : le premier est une variable de type tableau dynamique, le deuxième paramètre est le nombre d'éléments que le tableau doit pouvoir contenir. Par la suite, lorsque vous désirerez redimensionner un tableau dynamique, il suffira de rappeler "SetLength" avec une taille différente. Il est également possible de connaître la taille actuelle d'un tableau dynamique en utilisant la fonction 'Length'. 'Length' accepte un unique paramètre qui doit être une variable de type tableau dynamique.
L'exemple ci-dessous illustre ce que nous venons de voir : un tableau dynamique va être utilisé. Les explications seront données; comme d'habitude, après le code source :
Un tableau dynamique à une dimension est de la forme :
array of type_de_base
où type_de_base, comme pour les tableaux non dynamiques, est le type des éléments stockés dans le tableau. Vous remarquez que la partie qui donnait auparavant les dimensions, les bornes et les limites du tableau (la partie entre crochets) est justement absente pour les tableaux dynamiques.
Ces derniers tableaux sont plus complexes à manipuler que les tableaux standards : déclarer une variable de type tableau dynamique ne suffit pas, comme dans la plupart des autres cas de variables, pour que la variable soit utilisable. Du fait que leur taille n'est pas fixe, il faudra la gèrer en même temps que le tableau lui-même et donc fixer le nombre d'éléments avant la première utilisation du tableau au moyen d'une procédure : 'SetLength'. 'SetLength' accepte plusieurs paramètres : le premier est une variable de type tableau dynamique, le deuxième paramètre est le nombre d'éléments que le tableau doit pouvoir contenir. Par la suite, lorsque vous désirerez redimensionner un tableau dynamique, il suffira de rappeler "SetLength" avec une taille différente. Il est également possible de connaître la taille actuelle d'un tableau dynamique en utilisant la fonction 'Length'. 'Length' accepte un unique paramètre qui doit être une variable de type tableau dynamique.
L'exemple ci-dessous illustre ce que nous venons de voir : un tableau dynamique va être utilisé. Les explications seront données; comme d'habitude, après le code source :
|
Une variable locale de type tableau dynamique est déclarée. Les éléments stockés dans le tableau sont des chaînes de caractères. Le fait de déclarer une variable tableau dynamique ne suffit pas : avant son dimensionnement, elle ne contient pas de cellules. Ce nombre de cellules est fixé à 3 dans la première instruction par l'appel à 'SetLength'. Ceci permettra d'utiliser des cellules indexées de 0 à 2 (les index partent toujours de 0).
La deuxième instruction est plus délicate (il faut suivre les parenthèses, comme en mathématiques) : le tableau est donné en paramètre à la fonction 'Length' qui renvoie une valeur entière donnant le nombre de cases du tableau. Cette valeur entière est non pas stockée dans une variable mais directement donnée en paramètre à 'IntToStr' qui en fait une chaîne de caractères. Cette dernière est enfin directement transmise en tant que paramètre à 'ShowMessage' qui se chargera de l'afficher.
La troisième instruction initialise une case du tableau : la troisième (qui est indexée par 2). La 4ème affiche la chaîne 'coucou' en se servant de la valeur de la case du tableau. Enfin, la dernière instruction modifie la taille du tableau : il ne contient plus alors que 2 chaînes. La conséquence est que la chaîne dans l'ancienne troisième case est maintenant inaccessible : si on plaçait la quatrième instruction après la cinquième, une erreur serait signalée à la compilation ou à l'exécution.
Parlons maintenant un peu des tableaux dynamiques multidimensionnels : il n'est pas possible, dans la déclaration des tableaux dynamiques, de donner directement plusieurs dimensions : il faut utiliser une astuce : les éléments stockés dans le tableau à 1 dimension seront eux-mêmes des tableaux dynamiques à 1 dimension. Voici donc la déclaration d'un tableau dynamique à 2 dimensions contenant des entiers :
array of array of integer;
Il faut ici faire extrèmement attention à ne pas se tromper : ce n'est pas un vrai tableau multidimensionnel que nous avons ici : chaque case d'un tableau à une dimension contient un autre tableau. On est plus proche de ce qui suit :
La deuxième instruction est plus délicate (il faut suivre les parenthèses, comme en mathématiques) : le tableau est donné en paramètre à la fonction 'Length' qui renvoie une valeur entière donnant le nombre de cases du tableau. Cette valeur entière est non pas stockée dans une variable mais directement donnée en paramètre à 'IntToStr' qui en fait une chaîne de caractères. Cette dernière est enfin directement transmise en tant que paramètre à 'ShowMessage' qui se chargera de l'afficher.
La troisième instruction initialise une case du tableau : la troisième (qui est indexée par 2). La 4ème affiche la chaîne 'coucou' en se servant de la valeur de la case du tableau. Enfin, la dernière instruction modifie la taille du tableau : il ne contient plus alors que 2 chaînes. La conséquence est que la chaîne dans l'ancienne troisième case est maintenant inaccessible : si on plaçait la quatrième instruction après la cinquième, une erreur serait signalée à la compilation ou à l'exécution.
Parlons maintenant un peu des tableaux dynamiques multidimensionnels : il n'est pas possible, dans la déclaration des tableaux dynamiques, de donner directement plusieurs dimensions : il faut utiliser une astuce : les éléments stockés dans le tableau à 1 dimension seront eux-mêmes des tableaux dynamiques à 1 dimension. Voici donc la déclaration d'un tableau dynamique à 2 dimensions contenant des entiers :
array of array of integer;
Il faut ici faire extrèmement attention à ne pas se tromper : ce n'est pas un vrai tableau multidimensionnel que nous avons ici : chaque case d'un tableau à une dimension contient un autre tableau. On est plus proche de ce qui suit :
|
que de cela :
|
Je ne dis pas ça pour vous embêter mais pour vous préparer à une possilité intéressante de ce genre de tableau : Voici un exemple qui utilise un tableau dynamique à 2 dimensions. Le tableau est d'abord utilisé en tant que tableau classique, puis on prend partie du fait que chaque cellule est un tableau dynamique, et donc que rien n'oblige tous ces petits tableaux à avoir la même taille.
|
Dans l'exemple ci-dessus, une variable de type tableau dynamique est déclarée. Ce tableau comporte 2 dimensions. La première instruction fixe la taille du tableau. Après le paramètre tableau, 'SetLength' accepte en fait autant de paramètres que le tableau comporte de dimensions. Le premier paramètre donne la taille dans la première dimension (que nous assimilerons ici à des lignes) : 10 lignes. La deuxième valeur donne le nombre de colonnes par ligne, à savoir 20. Le résultat est donc un tableau de 10 cellules par 20. La deuxième instruction donne un exemple d'utilisation d'un tel tableau : les deux dimensions sont données dans un seul crochet, ce qui peut paraître bizarre du fait que TabTest2 est plus un tableau de tableaux qu'un tableau à deux dimensions : c'est une commodité offerte par le langage. Il faudrait normalement écrire :
|
écriture qui sera bien entendu acceptée par Delphi 5. La troisième instruction redimensionne le tableau en plus petit. C'est la même instruction que la première, avec des tailles différentes. La quatrième instruction vous montre la puissance de ce genre de tableaux : chaque cellule de la première dimension étant elle-même en fait un tableau dynamique à une dimension, il est possible de donner une taille différente à chacune de nos « lignes ». On obtient un tableau qui n'a plus rien de rectangulaire, mais qui pourra à l'occasion se montrer très utile. La dernière instruction se contente de donner une valeur à l'une des cases. Le texte en commentaire rappelle que cette case existe dans la deuxième ligne mais pas dans la première.
Si vous ne voyez pas vraiment l'intérêt de ces tableaux dynamiques, sachez que tout ceci est un petit avant-goût de la puissance des pointeurs, que nous verrons un peu plus tard. Si vous n'avez pas accès aux tableaux dynamiques à cause de votre version de Delphi, sachez que ces pointeurs vous permettrons de réaliser la même chose, en plus compliqué toutefois.
Si vous ne voyez pas vraiment l'intérêt de ces tableaux dynamiques, sachez que tout ceci est un petit avant-goût de la puissance des pointeurs, que nous verrons un peu plus tard. Si vous n'avez pas accès aux tableaux dynamiques à cause de votre version de Delphi, sachez que ces pointeurs vous permettrons de réaliser la même chose, en plus compliqué toutefois.
VII-G. Enregistrements
VII-G-1. Vue d'ensemble sur les enregistrements
Les enregistrements sont des types puissants de Pascal Objet : ils sont entièrement personnalisables. Le principe est de rassembler en un seul bloc des données diverses qu'il aurait autrement fallu stocker dans des endroits séparés. Les enregistrements permettront en quelque sorte de définir des moules à partir desquels seront obtenues des variables et des constantes.
Imaginons par exemple que vous ayez besoin dans une application de manipuler des informations relatives à un unique élément. Nous prendrons par exemple un logiciel : vous manipulerez entre autres son nom, sa version, sa langue, son occupation en espace disque. Pour manipuler l'un de ces éléments, vous pourriez déclarer 4 variables destinées chacune à stocker une information sur ce logiciel, mais cela deviendrait rapidement long et fastidieux. Il serait bien plus avantageux de n'avoir à déclarer qu'une seule variable capable de stocker toutes ces informations. Les enregistrements répondent à cette demande. Ils permettent, via la création d'un nouveau type, de créer des variables « à tiroirs ». Un type enregistrement se déclare comme suit :
Imaginons par exemple que vous ayez besoin dans une application de manipuler des informations relatives à un unique élément. Nous prendrons par exemple un logiciel : vous manipulerez entre autres son nom, sa version, sa langue, son occupation en espace disque. Pour manipuler l'un de ces éléments, vous pourriez déclarer 4 variables destinées chacune à stocker une information sur ce logiciel, mais cela deviendrait rapidement long et fastidieux. Il serait bien plus avantageux de n'avoir à déclarer qu'une seule variable capable de stocker toutes ces informations. Les enregistrements répondent à cette demande. Ils permettent, via la création d'un nouveau type, de créer des variables « à tiroirs ». Un type enregistrement se déclare comme suit :
|
nom_de_type désigne le nom par lequel le nouveau type enregistrement sera accessible. le mot Pascal réservé record débute un bloc de déclaration de membres, qui est terminé par le mot réservé end suivi comme d'habitude d'un point-virgule.
Ce bloc de déclarations de membres permet de décrire ce que contiendra une variable ou constante de ce type. Ce bloc est presque identique à un bloc de déclaration de variables, mis à part le mot réservé var qui est alors omis, et bien entendu le fait qu'on ne déclare absolument pas des variables mais qu'on décrit plutôt la structure du type : ce qu'il contiendra et sous quelle forme.
La déclaration de type ci-dessous déclare un type enregistrement pouvant contenir les informations d'un logiciel :
Ce bloc de déclarations de membres permet de décrire ce que contiendra une variable ou constante de ce type. Ce bloc est presque identique à un bloc de déclaration de variables, mis à part le mot réservé var qui est alors omis, et bien entendu le fait qu'on ne déclare absolument pas des variables mais qu'on décrit plutôt la structure du type : ce qu'il contiendra et sous quelle forme.
La déclaration de type ci-dessous déclare un type enregistrement pouvant contenir les informations d'un logiciel :
|
La présentation suggérée ici est à mon sens la meilleure car très lisible et revélatrice de la structure du bloc. Mis à part cette considération purement esthétique, un nouveau type nommé 'TLogiciel' (Rappel : par convention, les noms de types personnalisés, et en particulier les types enregistrement, commencent par un T majuscule, suivi d'un descriptif. C'est, au même titre que la présentation du code source, la convention adoptée par les créateurs de Delphi).
Concrètement, ce nouveau type permettra d'utiliser quatre membres : 'Nom', 'Version', 'Langue' et 'Taille' de types donnés dans la déclaration du type. On pourra ensuite déclarer des variables ou des constantes de ce type (note : il est possible mais vraiment peu recommandable de déclarer directement une variable de type enregistrement sans avoir créé ce type dans un bloc de déclaration de type. Il y a de bonnes raisons à cela : si vous voulez les connaître et voulez quand même utiliser cette possibilité, allez voir dans l'aide en ligne de Delphi.
En ce qui concerne les variables de type enregistrement, la variable en tant que telle ne nous intéresse pas vraiment, c'est plutôt son contenu qui nous intéresse. Pour accéder à un membre, il faut le qualifier, c'est-à-dire utiliser le nom d'une constante ou d'une variable qui contient un tel membre, la faire suivre d'un point et enfin du nom du membre. Ce membre se comporte alors respectivement comme une constante ou une variable du type déclaré pour ce membre dans la déclaration du type. Voici un exemple pour éclairer tout cela :
Concrètement, ce nouveau type permettra d'utiliser quatre membres : 'Nom', 'Version', 'Langue' et 'Taille' de types donnés dans la déclaration du type. On pourra ensuite déclarer des variables ou des constantes de ce type (note : il est possible mais vraiment peu recommandable de déclarer directement une variable de type enregistrement sans avoir créé ce type dans un bloc de déclaration de type. Il y a de bonnes raisons à cela : si vous voulez les connaître et voulez quand même utiliser cette possibilité, allez voir dans l'aide en ligne de Delphi.
En ce qui concerne les variables de type enregistrement, la variable en tant que telle ne nous intéresse pas vraiment, c'est plutôt son contenu qui nous intéresse. Pour accéder à un membre, il faut le qualifier, c'est-à-dire utiliser le nom d'une constante ou d'une variable qui contient un tel membre, la faire suivre d'un point et enfin du nom du membre. Ce membre se comporte alors respectivement comme une constante ou une variable du type déclaré pour ce membre dans la déclaration du type. Voici un exemple pour éclairer tout cela :
|
L'exemple ci-dessus déclare le type TLogiciel, puis deux variables de ce type. Mis à part la nouvelle forme de déclaration des types enregistrement, le principe reste le même qu'avec les autres types, à savoir qu'on définit au besoin un nouveau type, puis qu'on l'utilise dans la définition de variables ou de constantes (Nous verrons les constantes après cet exemple). Les deux instructions de la procédure sont des affectations. Dans la première, on affecte une chaîne au membre 'Nom' de la variable 'Log1' (cette variable est de type TLogiciel donc contient bien un membre nommé 'Nom'). 'Log1' étant une variable, 'Log1.Nom' est alors utilisable comme une variable, de type 'string' en l'occurence. On peut donc lui affecter une valeur chaîne.
La deuxième instruction est plus simple : c'est une affectation toute simple. La valeur d'une variable est affectée à une autre. Cette instruction affecte les valeurs de chacun des membres. On aurait pu faire la même chose en écrivant :
La deuxième instruction est plus simple : c'est une affectation toute simple. La valeur d'une variable est affectée à une autre. Cette instruction affecte les valeurs de chacun des membres. On aurait pu faire la même chose en écrivant :
|
ce qui a pour inconvénient majeur d'être plus long et de poser un problème si on modifie le type 'TLogiciel'. Imaginez en effet qu'on ajoute un membre nommé 'Auteur'; il faudrait, dans l'exemple ci-dessus, ajouter une affectation, alors que l'affectation de Tab1 à Tab2 ne changera pas.
L'exemple de type enregistrement donné est assez simple. Rien n'interdit d'utiliser des membres de types plus complexes. L'exemple ci-dessous est basé sur TLogiciel, mais introduit des changements intéressants.
L'exemple de type enregistrement donné est assez simple. Rien n'interdit d'utiliser des membres de types plus complexes. L'exemple ci-dessous est basé sur TLogiciel, mais introduit des changements intéressants.
|
Dans cet exemple, un nouveau type énuméré a été créé pour spécifier la langue d'un logiciel. On prévoit le cas où la langue ne serait pas parmi les cas prévus en donnant la valeur 'llAutre'. Dans ce cas, un membre 'LangueNom' de 'TLogiciel' sera utilisé pour stocker une chaîne décrivant la langue. Tout le reste n'est que très conventionnel.
En ce qui concerne les constantes de type enregistrement, l'exemple suivant devrait vous faire comprendre comment on procède pour les déclarer :
En ce qui concerne les constantes de type enregistrement, l'exemple suivant devrait vous faire comprendre comment on procède pour les déclarer :
|
On donne la valeur de chaque membre au moyen de : membre : valeur. La liste des valeurs est délimitée par des point-virgules et est mise entre parenthèses.
Le type enregistrement n'est évidemment pas un type ordinal, mais par contre, il peut être utilisé dans des tableaux (y compris dynamiques) et dans d'autres types enregistrements. Par exemple :
Le type enregistrement n'est évidemment pas un type ordinal, mais par contre, il peut être utilisé dans des tableaux (y compris dynamiques) et dans d'autres types enregistrements. Par exemple :
|
Cet exemple montre déjà des types bien élaborés. Les deux premiers types sont respectivement énumérés et enregistrement. Le troisième ('TLogiciel') utilise comme type d'un de ses membres un type enregistrement. Si nous avions une variable 'Log1' de type 'TLogiciel', il faudrait écrire 'Log1.Langue.Code' pour accéder au code de la langue du logiciel. Le dernier type est encore un peu plus difficile : c'est un tableau dynamique, dont les éléments sont de type 'TLogiciel'. Imaginons que nous ayons une variable de ce type nommée 'Logiciels' : pour accèder au code de la langue du troisième logiciel de ce tableau, il faudrait écrire 'Logiciels[2].Langue.Code'. car 'Logiciels[2]' est de type 'TLogiciel' et 'Logiciels[2].Langue' est donc de type 'TLangue'.
Ce dernier type vous parait peut-être bien délicat, mais imaginez qu'avec ce type, on peut gèrer sans trop de peine une liste de logiciels, avec leurs particularités respectives, et tout cela avec une seule variable.
Ce dernier type vous parait peut-être bien délicat, mais imaginez qu'avec ce type, on peut gèrer sans trop de peine une liste de logiciels, avec leurs particularités respectives, et tout cela avec une seule variable.
VII-G-2. Manipulation avancée des enregistrements
Il peut rapidement devenir fastidieux d'écrire le préfixe « variable. » devant les membres d'un enregistrement. Pour cela il existe une technique : l'utilisation d'un bloc with. Ce dernier permet, à l'intérieur d'un bloc spécifique, de manipuler les membres d'un enregistrement comme s'ils étaient directement accessibles (sans avoir à écrire « variable. »). Ce bloc est considéré comme une instruction unique. Voici sa syntaxe :
|
Le mot Pascal réservé with commence l'instruction. Vient ensuite une constante, un paramètre ou une variable de type enregistrement, puis le mot réservé do suivi d'une unique instruction. Cette instruction peut utiliser les membres de la donnée entre 'with' et 'do' sans passer par « variable. ». Mais il est possible de remplacer instruction par un bloc d'instructions. Un bloc d'instructions se comporte comme une instruction unique, mais est composé de plusieurs instructions. On utilise pour le créer les mots Pascal réservés begin et end entre lesquels on écrit les instructions, comme on le ferait pour une procédure ou une fonction. Voici un exemple :
|
Dans l'exemple ci-dessus, TLogiciel est tel qu'il a été créé dans les exemples précédents. La procédure ne contient qu'une seule instruction : un bloc with. Ce bloc permet d'accèder aux membres de la variable Log1 sans qualifier ses membres. Le bloc est utilisé pour initialiser la variable. Il faut bien comprendre ici que chaque instruction à l'intérieur du bloc with devrait être adaptée pour fonctionner en dehors de ce bloc, mais que ce sont bel et bien des instructions réunies en une seule grâce aux deux mots réservés begin et end.
Il est dés lors possible, du fait que les instructions à l'intérieur d'un bloc with sont de vraies instructions, d'écrire un bloc with à l'intérieur d'un autre. Il faudra donner comme paramètre une donnée qui n'a rien à voir avec 'Log1' ou un membre de 'Log1' (with n'accepte que des enregistrements). Voici par exemple ce qu'il est possible de faire dans notre cas :
Il est dés lors possible, du fait que les instructions à l'intérieur d'un bloc with sont de vraies instructions, d'écrire un bloc with à l'intérieur d'un autre. Il faudra donner comme paramètre une donnée qui n'a rien à voir avec 'Log1' ou un membre de 'Log1' (with n'accepte que des enregistrements). Voici par exemple ce qu'il est possible de faire dans notre cas :
|
Je n'en dirai pas plus, sauf qu'il faudra éviter d'utiliser ce type de bloc à tort et à travers : il faudra avoir au minimum 2 à 3 manipulations sur les membres d'un enregistrement pour passer par un bloc with.
VII-H. Types et paramètres de procédures et fonctions
Tout ce verbiage sur les types nous a (presque) fait oublier que les types sont utilisés à un autre endroit important : dans les déclarations de fonctions et procédures, pour donner les types des paramètres et le type de résultat pour une fonction.
Et ici se pose un petit problème : une partie seulement des types que nous venons de voir sont acceptés pour les paramètres et pour le résultat d'une fonction sous Delphi 2 (Dans Delphi 5, tous les types sont autorisés). Je n'ai pas encore pu faire de tests sous Delphi 2, 3 et 4, donc il convient de se limiter aux types ordinaux et aux chaînes de caractères (ce qui inclue les types énumérés et les booléens).
Et ici se pose un petit problème : une partie seulement des types que nous venons de voir sont acceptés pour les paramètres et pour le résultat d'une fonction sous Delphi 2 (Dans Delphi 5, tous les types sont autorisés). Je n'ai pas encore pu faire de tests sous Delphi 2, 3 et 4, donc il convient de se limiter aux types ordinaux et aux chaînes de caractères (ce qui inclue les types énumérés et les booléens).
VII-I. Conclusion et retour sur terre
Au terme de ce chapitre consacré aux types de données, vous admettrez certainement que je vous ai ennuyé. C'est sûrement très vrai et je m'en excuse.
Ces types de données, pourtant, vous allez souvent les utiliser dans les programmes que vous écrirez. Le chapitre qui suit est davantage concentré sur les instructions en Pascal que sur les déclarations de toutes sortes. Vous apprendrez surtout qu'un programme est rarement exécuté de manière linéaire, mais que l'exécution peut « sauter » des instructions ou en répeter certaines.
Ces types de données, pourtant, vous allez souvent les utiliser dans les programmes que vous écrirez. Le chapitre qui suit est davantage concentré sur les instructions en Pascal que sur les déclarations de toutes sortes. Vous apprendrez surtout qu'un programme est rarement exécuté de manière linéaire, mais que l'exécution peut « sauter » des instructions ou en répeter certaines.
آخر مواضيع منتدى نقاش المغرب العربي
دعاء الرحمة للوالدين
الأجـــــور المضاعفة فـــي الميـــزان
خمسون فكرة لعمل الخير
التجارة الرابحة مع الله
تاريخ الحركات الجهادية المعاصرة: كتاب "تجلية الراية"
دور الانحلال العقائدي في سقوط الدول: كتاب "مصارع الدول"
أيسر الطرق لدعوة غير العرب إلى الله
بعض الأعمال التي تثبت بها قدمك عند عبورك الصراط المستقيم
ذكر الله أكبر
ألا تحبون ان يغفر الله لكم
حكم حملة صلاه على الرسول صلى الله عليه وسلم
الرد على شبهة أن الرسول يقر العبودية والرق د. راغب السرجاني
تم معالجته بسورة البقره
كلمات عظيمة عن فضل الصدقة مع ذكر بعض فوائدها العجيبة
بكت عيني ... فماذا أنت فاعل؟
كلمات من ثلاث احرف
شرح نزهة النظر: لفضيلة الشيخ أبي عبد الله محمد سعيد رسلان حفظه الله تعالى
الفوائد العشرة لغض البصر
مشروع ضخم جدا لخدمة القرآن ثروة لا تقدر بثمن
الختمه المجوده للقراء ( عبدالباسط عبدالصمد - المنشاوي - الحصري)
Aucun commentaire:
Enregistrer un commentaire