| 
   | c_list_of_double - John COLIBRI. |   
résumé : encapsulation de liste de valeurs réelles, en utilisant des ARRAY OF, des tList de ^Double et des tList de c_double
mots clé : liste de doubles - encapsulation - techniques objet - tList - série numérique - Vecteur - calcul matriciel - New - pointeurs
logiciel utilisé : Windows XP personnel, Delphi 6.0
matériel utilisé : Pentium 2.800 Mhz, 512 Meg de mémoire, 250 Giga disque dur
champ d'application : Delphi 5, Delphi 6, Delphi 6, Delphi 6, Delphi 2006, Turbo Delphi, Delphi 2007 sur Windows
niveau : développeur Delphi
plan :
   
 1 - Liste de RéelsPour réaliser des traitements scientifiques, il est fréquent d'avoir à utiliser des tableaux ou des liste de réels, en général de type Double. Lorsque la taille de la série est inconnue à la compilation, il faut armer un
série pouvant être dimensionnée, ou redimensionnée par l'utilisateur. Nous allons présenter ici une CLASS Delphi et d'autres techniques de programmation Objet Delphi permettant cette encapsulation de listes de valeurs numériques.  
 
 
 2 - Encapsulation de liste de Double2.1 - Les techniques StandardSi nous connaissons la taille de la série à utiliser, par exemple 1000 ou 1024 points, nous pouvons utiliser:    | VAR tableau: ARRAY[0..999] OF Double |   Ici, c'est le programmeur Delphi qui a figé la taille du tableau. Cela fonctionne parfaitement si l'utilisateur a exactement besoin de 1000 Doubles. En revanche, si l'utilisateur a besoin de 10 Doubles, il en a 990 de trop, et
s'il en a besoin de 1200, il lui en manque 200.   Depuis Delphi 2, nous pouvons utiliser des tableaux dynamiques, ou c'est l'utilisateur qui peut indiquer quelle taille de tableau il souhaite utiliser:  
nous déclarons une ARRAY OF (sans donner les bornes initiales et finales du tableau):     | VAR tableau_dynamique: ARRAY OF Double |   Ceci peut être représenté par le schéma suivant:     nous demandons à l'utilisateur de fournir la taille. Il tape par exemple
cette taille dans un tEdit, et nous dimensionnons le tableau dans un tButton.OnClick:     | l_taille:= IntToStr(Edit1.Text); SetLength(tableau_dynamique, l_taille);
 
 |   Supposons  que l'utilisateur demande 3 cellules. Delphi alloue les 3
cellules:     l'utilisateur ajoute ses valeurs dans le tableau, exactement comme pour un tableau statique:   
 | tableau_dynamique[0]:= 3.14; tableau_dynamique[1]:= -45.67;
 
 |   soit:  
  s'il change d'avis, et modifie la taille du tableau, Delphi redimensionne le tableau. Supposons que l'utilisateur décide d'agrandir son tableau à 7
cellules. Pour cela, il exécute simplement la même instruction SetLength avec la même valeur:     | SetLength(tableau_dynamique, 7); 
 |   et l'allocateur mémoire de Delphi va:  
chercher en mémoire un espace assez grand pour contenir nos 7 cellules, et va le réserver en le remplissant de 0   
il va copier les valeurs du tableau actuel au début de la nouvelle zone:    il va faire pointer notre variable tableau_dynamique vers la nouvelle
zone et rendre l'ancienne zone (de 3 cellules) au système    la fonction Length permet à chaque instant de connaître la taille. Par
exemple, un développeur prudent vérifiera que l'utilisateur n'essaye pas de lire ou écrire un zone en dehors du tableau:     | IF indice< Length(tableau_dynamique) THEN tableau_dynamique[indice]:= valeur
 ELSE ShowMessage('débordement d''indice');
 
 |  
et finalement, lorsque nous souhaitons libérer la mémoire contenant les cellules, nous affectons simplement NIL au tableau:   
 
 Notez que:
  un ARRAY OF correspond à un pointeur, et SetLength alloue les données
contenues dans le tableau. Mais le compilateur gère cette allocation, et lorsque nous souhaitons accéder aux données, nous n'avons pas besoin d'utiliser le symbole ^
de plus l'allocation / libération est réalisée en utilisant SetLength et l'affectation de NIL (et non pas via NEW et DISPOSE, comme pour les pointeurs ordinaires)
 
 Nous constatons alors que nous disposons bien de toutes les fonctionnalités pour gérer des tableaux de n'importe quelle taille. Toutefois, cela nous oblige à truffer notre code utilisateur de nombreux tests et appels à des routines de
gestion des tableaux dynamiques. En fait, vu du point de vue de 'utilisateur, tout ce qu'il souhaite est
  créer son tableau
ajouter quelques valeur, et ceci sans provoquer d'erreur de débordement
pouvoir accéder aux valeurs de son tableau pour modifier des valeurs, ou les lire, avec la syntaxe la plus légère possible.
 
 Compte tenu de cet énoncé du problème, la solution pour un développeur Delphi
est instantannée: il faut créer une CLASS qui encapsule nos instructions Delphi et représente un liste de Double.
  
 
 2.2 - La première CLASSe encapsulant un ARRAY OF DoubleVoici la définition de notre CLASS c_double_list:    | c_array_of_double= Class m_array_of_double: ARRAY of Double;
 m_count: Integer;
 
 
                     Constructor create;procedure add_double(p_double: Double);
 function f_double(p_index: Integer): Double;
 Destructor Destroy; Override;
 end; // c_array_of_double
 
 |  
et:   Et voici les procédures correspondantes:m_array_of_double contiendra, comme ci-dessus, les Doubles
le CONSTRUCTOR va initialiser la CLASS
add_double permet d'ajouter des valeurs au tableau
f_double récupère une valeur
     | Constructor c_array_of_double.create; begin
 InHerited Create;
 end; // create
 
 
procedure c_array_of_double.add_double(p_double: Double);begin
 if m_count>= Length(m_array_of_double)
 then
 if Length(m_array_of_double)= 0
 then SetLength(m_array_of_double, 1)
 else SetLength(m_array_of_double, 2* Length(m_array_of_double));
 
      m_array_of_double[m_count]:= p_double;Inc(m_count);
 end; // add_double
 
 
function c_array_of_double.f_double(p_index: Integer): Double;begin
 if p_index>= Length(m_array_of_double)
 then Raise Exception.Create('p_index> m_count');
 
      Result:= m_array_of_double[p_index];end; // f_double
 
  Destructor c_array_of_double.destroy;begin
 m_array_of_double:= Nil;
 
 
    Inherited;end; // destroy
 
 |   
 Et voici un exemple de programme utilisant notre CLASSe:
     | var g_c_array_of_double: c_array_of_double= Nil; 
 
procedure TForm1.create_arrayClick(Sender: TObject);begin
 g_c_array_of_double:= c_array_of_double.Create;
 end; // create_arrayClick
 
 
procedure TForm1.add_doublesClick(Sender: TObject);begin
 if g_c_array_of_double= Nil
 then g_c_array_of_double.Create;
 
 
    g_c_array_of_double.add_double(1.1);g_c_array_of_double.add_double(2.2);
 g_c_array_of_double.add_double(3.3);
 g_c_array_of_double.add_double(4.4);
 end; // add_doubles_Click
 
 
procedure TForm1.display_doublesClick(Sender: TObject);var l_index: Integer;
 begin
 for l_index:= 0 to g_c_array_of_double.m_count- 1 do
 Memo1.Lines.Add(FloatToStr(g_c_array_of_double.f_double(l_index)));
 end; // display_doubles_Click
 
 
procedure TForm1.free_doubleClick(Sender: TObject);begin
 g_c_array_of_double.Free;
 g_c_array_of_double:= Nil;
 // or : FreeAndNil(g_c_array_of_double);
 end; // free_double_Click
 
 |   
 Notez que:
  nous n'avons pas donné de dimension initiale à notre tableau. La première
addition se chargera de donner la taille qu'il faut à notre tableau
notre encapsulation est loin d'être parfaite: l'utilisateur doit encore accéder à g_c_array_of_double.m_array_of_double, et utiliser
g_c_array_of_double.m_count
 
 Pour mieux rendre notre représentation opaque à l'utilisateur, nous allons
  Voici alors la nouvelle CLASSe:créer une PROPERTY Doubles et les deux méthodes set_double et
get_double correspondantes
créer une PROPERTY Count
  Et voici l'image de notre application complète:sa définition:     | const k_granularity= 4; 
  type c_array_of_double_2=Class
 private
 m_array_of_double: ARRAY of Double;
 m_count: Integer;
 
 
            function get_double(p_index: Integer): Double;procedure set_double(p_index: Integer; p_double: Double);
 public
 Constructor create;
 procedure add_double(p_double: Double);
 
 
            procedure set_length(p_length: Integer);
              Destructor Destroy; Override;
 
            Property Doubles[p_index: Integer] : Doubleread get_double write set_double; Default;
 Property Count: Integer read m_count write m_count;
 end; // c_array_of_double
 
 |   son implémentation     | Constructor c_array_of_double_2.create; begin
 InHerited Create;
 SetLength(m_array_of_double, k_granularity);
 end; // create
 
 
procedure c_array_of_double_2.add_double(p_double: Double);begin
 if m_count>= Length(m_array_of_double)
 then SetLength(m_array_of_double, 2* Length(m_array_of_double));
 
      m_array_of_double[m_count]:= p_double;Inc(m_count);
 end; // add_double
 
 
function c_array_of_double_2.get_double(p_index: Integer): Double;begin
 if p_index>= Length(m_array_of_double)
 then Raise Exception.Create('p_index> m_count');
 
      Result:= m_array_of_double[p_index];end; // get_double
 
 
procedure c_array_of_double_2.set_double(p_index: Integer; p_double: Double);begin
 if p_index>= Length(m_array_of_double)
 then begin
 m_count:= p_index+ 1;
 SetLength(m_array_of_double, m_count);
 end;
 
 
    m_array_of_double[p_index]:= p_double;end; // set_double
 
 
procedure c_array_of_double_2.set_length(p_length: Integer);begin
 m_array_of_double:= Nil;
 
 
    m_count:= p_length;SetLength(m_array_of_double, m_count);
 end; // set_length
 
 
Destructor c_array_of_double_2.destroy;begin
 m_array_of_double:= Nil;
 
      Inherited;end; // destroy
 
 |   et un exemple d'utilisation:     | var g_c_array_of_double_2: c_array_of_double_2= Nil; 
 
procedure TForm1.create_array_2Click(Sender: TObject);begin
 g_c_array_of_double_2:= c_array_of_double_2.Create;
 end; // create_array_2Click
 
 
procedure TForm1.add_doubles_2Click(Sender: TObject);begin
 g_c_array_of_double_2.set_length(4);
 
 
    g_c_array_of_double_2[0]:= 10.0;g_c_array_of_double_2[1]:= 20.0;
 g_c_array_of_double_2[2]:= 40.0;
 g_c_array_of_double_2[3]:= 40.0;
 
 
    g_c_array_of_double_2[4]:= 50.0;g_c_array_of_double_2[5]:= 60.0;
 end; // add_doubles_2Click
 
 
procedure TForm1.display_double_2Click(Sender: TObject);var l_index: Integer;
 begin
 Memo1.Lines.Add('nombre '+ IntToStr(g_c_array_of_double_2.Count));
 for l_index:= 0 to g_c_array_of_double_2.Count- 1 do
 Memo1.Lines.Add(FloatToStr(g_c_array_of_double_2[l_index]));
 end; // display_double_2Click
 
 
procedure TForm1.free_double_2Click(Sender: TObject);begin
 FreeAndNil(g_c_array_of_double_2);
 end; // free_double_2Click
 
 |  
 
   
 Notez que:
  dans cet exemple nous avons commencé par donner une taille initiale dans le
CONSTRUCTOR (4 dans notre cas). Une autre possibilité encore aurait été de doter le CONSTRUCTOR d'un paramètre p_taille_initiale
pour redimensionner le tableau
 
nous vérifions à chaque utilisation d'un indice, que celui-ci est bien dans la plage des valeurs actuellement permises. Si ce n'est pas le cas, nous redimensionnons automatiquement le tableau
pour redimensionner le tableau, plusieurs stratégies sont possibles:
  soit augmenter le tableau d'une cellule à la fois. Il a 3 cellules, l'utilisateur en veut une de plus, eh bien nous en allouons une de
plus et il a a présent un tableau de 4 cellules, puis 5 cellules    soit augmenter d'une quantité fixe. Par exemple 10 ou 16. Dans notre
exemple, si nous augmentons de 2, il a 3 au départ, puis 5, 7, 9 etc:    soit utiliser le système "Buddy-Buddy" qui consiste à doubler la
taille à chaque réallocation. Nous commençons par exemple à 3, puis augmentons à 6, 12, 24 etc.   Dans les deux derniers cas, il faut gérer deux variables
 
la taille allouée (fournie par Length())
le nombre de cellules actuellement utilisées, contenu dans m_count
nous avons aussi décidé de laisser l'utilisateur taper n'importe que indice,
en allouant au besoin ce qu'il faut entre la taille actuelle du tableau et la cellule demandée par l'utilisateur. Par exemple:  Cette stratégie est astucieuse, mais, en fonction du problème à traiter peut être risquée. Par exemple, si l'utilisateur se trompe et tape 110 au lieu de
10, notre CLASS lui fournira, sans rien lui dire, un tableau plus grand qu'il ne le souhaitait. Plusieurs solutions si vous souhaitez éviter ces redimensionnements automatiques:la taille actuelle est de 23
l'utilisateur veut modifier la cellule 34
nous allons les cellules entre 24 et 32 en les remplissant de 0
 
tester l'indice demandé, et provoquer une exception si l'utilisateur dépasse la limite qu'il a initialement demandé
forcer le dimensionnement lors de l'appel du CONSTRUCTOR, et ne pas redimensionner par la suite
 
 
 2.3 - Utilisation d'une tList de ^DoubleAu lieu d'utiliser un ARRAY OF Double, nous pouvons utiliser une tList, qui a l'avantage essentiel que c'est Delphi qui se charge de l'allocation /
réallocation des cellules. Nous appelons simplement tList.Add(xxx) et cette instruction ajoute une nouvelle cellule. En fait, la tList utilise un mécanisme similaire au nôtre:
Le seul problème est que la table de données utilisée, appelée tList.Items, n'est pas prévue pour contenir des Doubles, mais de Pointer: un pointeur générique, de taille 4 octets.lors de la création, une table de 16 cellules est allouée (c'est la Granularity de la tList), et Count est égal à 0
lorsque nous appelons Add :
 
si Count est inférieur à la taille allouée, la valeur est placée après la dernière valeur utilisée
dans le cas contraire, la taille allouée est doublée (système Buddy-Buddy) et la valeur est placée après la dernière valeur utilisée
 
Il nous faut donc placer chaque Double dans une autre cellule, associée à la cellule courante. Nous pouvons utiliser deux techniques:   utiliser des pointeurs de Double, et stocker nos doubles dans chaque cellule pointée
utiliser une CLASS c_double qui contiendra nos doubles
 
 Commençons par la première technique
  Pour cela:  
 Notez:
 
 A présent, voici donc une CLASS qui a exactement la même fonctionnalité que la CLASS précédente, mais qui utilise des pointeurs de Double:
  voici la définition de la CLASSe: 
   | type t_pt_double= ^Double; 
 
     c_tlist_of_pt_double=Class(tList)
 Private
 function get_double(p_index: Integer): Double;
 procedure set_double(p_index: Integer; p_double: Double);
 
             PublicConstructor create;
 procedure add_double(p_double: Double);
 Destructor Destroy; Override;
 
 
             Property Doubles[p_index: Integer] : Double Read get_double Write set_double; Default;
 end; // c_tlist_of_pt_double
 
 |   et son implémentation:     | Constructor c_tlist_of_pt_double.create; begin
 Inherited Create;
 end; // create
 
 
procedure c_tlist_of_pt_double.add_double(p_double: Double);var l_pt_double: t_pt_double;
 begin
 New(l_pt_double);
 l_pt_double^:= p_double;
 Inherited Add(l_pt_double);
 end; // add_double
 
 
function c_tlist_of_pt_double.get_double(p_index: Integer): Double;var l_pt_double: t_pt_double;
 begin
 if p_index>= Count
 then Raise Exception.Create('p_index> m_count');
 
      Result:= t_pt_double(Items[p_index])^;end; // get_double
 
 
procedure c_tlist_of_pt_double.set_double(p_index: Integer; p_double: Double);var l_index: Integer;
 begin
 // -- if index beyond Count, create with 0 filled cells
 if p_index>= Count
 then
 For l_index:= Count to p_index do
 add_double(0);
 
 
    t_pt_double(Items[p_index])^:= p_double;end; // set_double
 
 
Destructor c_tlist_of_pt_double.destroy;var l_index: Integer;
 begin
 for l_index:= 0 To Count- 1 do
 Dispose(Items[l_index]);
 
      Inherited;end; // destroy
 
 |   en prime, un exemple d'utilisation:     | var g_c_tlist_of_pt_double: c_tlist_of_pt_double= Nil; 
 
procedure TForm1.create_listClick(Sender: TObject);begin
 g_c_tlist_of_pt_double:= c_tlist_of_pt_double.Create;
 end; // create_arrayClick
 
 
procedure TForm1.add_doublesClick(Sender: TObject);begin
 if g_c_tlist_of_pt_double= Nil
 then g_c_tlist_of_pt_double.Create;
 
 
    g_c_tlist_of_pt_double.add_double(1.1);g_c_tlist_of_pt_double.add_double(2.2);
 g_c_tlist_of_pt_double.add_double(3.3);
 g_c_tlist_of_pt_double.add_double(4.4);
 end; // add_doubles_Click
 
 
procedure TForm1.display_doublesClick(Sender: TObject);var l_index: Integer;
 begin
 for l_index:= 0 to g_c_tlist_of_pt_double.Count- 1 do
 Memo1.Lines.Add(FloatToStr(g_c_tlist_of_pt_double.Doubles[l_index]));
 end; // display_doubles_Click
 
 
procedure TForm1.free_listClick(Sender: TObject);begin
 FreeAndNil(g_c_tlist_of_pt_double);
 end; // free_double_Click
 
 
procedure TForm1.set_4_directClick(Sender: TObject);begin
 if g_c_tlist_of_pt_double= Nil
 then g_c_tlist_of_pt_double.Create;
 
 
    g_c_tlist_of_pt_double.Doubles[3]:= 4.4;end; // set_4_directClick
 
 |   qui se présente ainsi:    
 
 Notez que
 
nous avons choisi de conserver add_double. Il aurait été possible d'utiliser Add, qui est plus traditionnel
si nous utilisons Add, il est impératif d'appeler INHERITED Add pour
ajouter le pointeur dans la liste (INHERITED n'aurait pas été nécessaire avec add_double, car la tList n'a aucune méthode ayant ce nom)
nous avons choisi d'hériter de tList. Il aurait été possible de placer dans
une c_tlist_of_pt_double un attribut m_c_tlist de type tList (comme nous avions inclus un attribut m_array_of_double dans la CLASS précédente). L'avantage de l'héritage est de bénéficier directement des propriétés et
méthodes de la tList (Count, Find etc). Si la tList est incluse (composition plutôt qu'héritage), il faut créer des PROPERTYes qui relaient les mêmes propriétés de la tList. Dans notre cas, l'héritage
semble avantageux. En revanche si nous souhaitons utiliser plusieurs tList (voir plus loin), nous n'aurons pas d'autre choix que de placer les tList dans la CLASSe
 
 Cette technique est certes utilisable, mais reste un peu étrange pour les nouveaux venus dans Delphi qui préféreraient éviter les pointeurs, qui ont, à cause de leur utilisation un peu délicate, une mauvaise réputation.
 
Nous pouvons donc effectuer le même traitement en créant un objet dont la seule vocation sera de contenir notre valeur Double   
 
 2.4 - Une tList de c_doublePour éviter les New et Dispose (qui fonctionnent parfaitement), nous pouvons utiliser une CLASS spéciale pour stocker chaque Double. Donc:   voici la définition des deux CLASSes:     | type c_double= Class
 m_double: Double;
 Constructor create(p_double: Double);
 end; // c_double
 
       c_tlist_of_c_double=Class(tList)
 Private
 function get_double(p_index: Integer): Double;
 procedure set_double(p_index: Integer; p_double: Double);
 
             PublicConstructor create;
 procedure add_double(p_double: Double);
 Destructor Destroy; Override;
 
 
             Property Doubles[p_index: Integer] : DoubleRead get_double Write set_double; Default;
 end; // c_tlist_of_c_double
 
 |   et leur implémentation:     | // -- c_double 
 
Constructor c_double.create(p_double: Double);begin
 Inherited Create;
 m_double:= p_double;
 end; // create
 
 
// -- c_tlist_of_c_double.
  Constructor c_tlist_of_c_double.create;begin
 Inherited Create;
 end; // create
 
 
procedure c_tlist_of_c_double.add_double(p_double: Double);begin
 Inherited Add(c_double.create(p_double))
 end; // add_double
 
 
function c_tlist_of_c_double.get_double(p_index: Integer): Double;begin
 if p_index>= Count
 then Raise Exception.Create('p_index> m_count');
 
      Result:= c_double(Items[p_index]).m_double;end; // get_double
 
 
procedure c_tlist_of_c_double.set_double(p_index: Integer; p_double: Double);var l_index: Integer;
 begin
 // -- if index beyond Count, create with 0 filled cells
 if p_index>= Count
 then
 For l_index:= Count to p_index do
 add_double(0);
 
 
    c_double(Items[p_index]).m_double:= p_double;end; // set_double
 
 
Destructor c_tlist_of_c_double.destroy;var l_index: Integer;
 begin
 for l_index:= 0 To Count- 1 do
 c_double(Items[l_index]).Free;
 
 
    Inherited;end; // destroy
 
 |   et le projet Delphi de test: 
   | var g_c_tlist_of_c_double: c_tlist_of_c_double= Nil; 
 
procedure TForm1.create_listClick(Sender: TObject);begin
 g_c_tlist_of_c_double:= c_tlist_of_c_double.Create;
 end; // create_arrayClick
 
 
procedure TForm1.add_doublesClick(Sender: TObject);begin
 if g_c_tlist_of_c_double= Nil
 then g_c_tlist_of_c_double.Create;
 
 
    g_c_tlist_of_c_double.add_double(1.1);g_c_tlist_of_c_double.add_double(2.2);
 g_c_tlist_of_c_double.add_double(3.3);
 g_c_tlist_of_c_double.add_double(4.4);
 end; // add_doubles_Click
 
 
procedure TForm1.display_doublesClick(Sender: TObject);var l_index: Integer;
 begin
 for l_index:= 0 to g_c_tlist_of_c_double.Count- 1 do
 Memo1.Lines.Add(FloatToStr(g_c_tlist_of_c_double.Doubles[l_index]));
 end; // display_doubles_Click
 
 
procedure TForm1.free_listClick(Sender: TObject);begin
 FreeAndNil(g_c_tlist_of_c_double);
 end; // free_double_Click
 
 |   dont voici l'image:    
 
 
 2.5 - Comparaison des trois techniquesNous pouvons facilement comparer les trois techniques par le schéma suivant:   
 Il en ressort que
 
l'utilisation d'un ARRAY OF double est certainement la plus économe au niveau mémoire, et évite en plus tout surtypage
l'emploi de pointeurs de Double est assez simple, mais nécessite une
allocation séparée pour chaque cellule, ce qui peut se révéler coûteux en temps. De plus il faut surtyper les éléments de la tList, au départ prévus pour contenir des Pointer et pas des Doubles^
la création de CLASSe c_double est relativement classique. C'est la technique Delphi la plus naturelle, et elle est utilisée pour encapsuler dans une tList n'importe quel autre type de cellule (une c_string, une
c_ma_classe qui contiendrait de nombreux champs). Mais il faut savoir que chaque objet contient un certain nombre d'octets pour gérer les CLASSe: la taille de l'objet, le pointeur vers la VMT (table des méthodes virtuelles)
etc. D'où un consommation nettement supérieure par rapport à une cellule de Double. En revanche, si nous encapsulons un Double dans une CLASSe, nous pouvons y associer, si nous le souhaitons des méthodes qui seraient utiles
pour notre application: vérifier que la valeur est comprise entre certaines bornes, afficher avec certains formats prédéfinis, sauvegarder dans un flux, ou relire un flux etc
 
 
 
 3 - Encapsulation de liste de BooleanLorsque la taille de chaque élément est inférieur à la taille de la cellule
d'une tList (un Pointer, soit 4 octets), nous pouvons stocker la valeur dans chaque cellule en utilisant le surtypage. Schématiquement nous avons, pour nos trois structures canoniques:  
  
 Et, très rapidement, le code avec stockage dans les Pointer de la tList:
  voici la définition de la CLASSe:     | c_tlist_of_boolean= Class(tList)
 Private
 function get_boolean(p_index: Integer): Boolean;
 procedure set_boolean(p_index: Integer; p_boolean: Boolean);
 
        PublicConstructor create;
 procedure add_boolean(p_boolean: Boolean);
 Destructor Destroy; Override;
 
 
        Property Booleans[p_index: Integer] : BooleanRead get_boolean Write set_boolean; Default;
 end; // c_tlist_of_boolean
 
 |   et leur implémentation:     | Constructor c_tlist_of_boolean.create; begin
 Inherited;
 end; // create
 
 
procedure c_tlist_of_boolean.add_boolean(p_boolean: Boolean);begin
 Inherited Add(Nil);
 if p_boolean
 then Items[Count- 1]:= Pointer(1);
 end; // add_boolean
 
 
function c_tlist_of_boolean.get_boolean(p_index: Integer): Boolean;begin
 if p_index>= Count
 then Raise Exception.Create('p_index> m_count');
 
      Result:= Integer(Items[p_index])> 0;end; // get_boolean
 
 
procedure c_tlist_of_boolean.set_boolean(p_index: Integer; p_boolean: Boolean);var l_index: Integer;
 begin
 // -- if index beyond Count, create with 0 filled cells
 if p_index>= Count
 then
 For l_index:= Count to p_index do
 add_boolean(False);
 
 
    if p_booleanthen Items[p_index]:= Pointer(1)
 else Items[p_index]:= Nil;
 end; // set_boolean
 
 
Destructor c_tlist_of_boolean.destroy;begin
 Inherited;
 end; // destroy
 
 |   et le résultat est: 
 
 
 Notez que
  nous avons ici exploité que False a la valeur 0 (et donc NIL pour un
Pointer) et True la valeur 1
l'exemple présenté peut être aisément adapté à des liste de Byte, ShortInt, SmallInt, Integer, Word, dWord, Char et WideChar, énuméré.
Bref, tout ce qui a moins de 4 octet
 
 
 
 4 - Liste de Plusieurs Doubles4.1 - Séries de plusieurs réelsSupposons à présent que nous souhaitions gérer des liste de plusieurs doubles: Dans ce cas, nous pouvons aussi mettre en place les mêmes alternatives:les valeurs X, Y, Z d'un point en 3D
les mesures électriques d'un composant (tension, intensité, fréquence etc)
les données économiques d'une série (date, prix, volume pour une série boursière)
 
définir un RECORD ou une CLASSe pour chaque groupe de valeurs, et utiliser un ARRAY OF t_record ou c_class, et gérer nous-mêmes la réallocation. Cette solution fonctionne, mais nous perdons la seule
motivation que nous avions pour un Double, qui était d'éviter le surtypage
utiliser une tList et placer les données dans un t_record^. Ici c'est à nouveau possible, mais en général, si déjà nous avons plusieurs valeurs à
gérer, il est plus que probable que nous aurons des traitements à réaliser sur chaque groupe de points (
l'utilisation d'un CLASS c_class s révèle en général la plus adaptée
 
 
 4.2 - ARRAY OF record_of_double ou record_of_double OF ARRAY OF DoubleEn utilisant des tableaux dynamiques, ARRAY OF, nous avons deux solutions: Schématiquement nous avons:soit placer nos chaque valeur multidimensionnelle dans un RECORD et créer
un ARRAY OF de ces RECORDs
soit créer un RECORD d'une c_array_of_double présenté ci-dessus
    
 Pour la première solution:
 
voici la définition des deux CLASSes:     | type t_double_record= Record m_x, m_y, m_z: Double;
 end; // t_double_record
 
 
     c_array_of_record_of_doubles=Class
 private
 m_array_of_double_record: ARRAY of t_double_record;
 m_count: Integer;
 
 
             function get_doubles(p_index: Integer): t_double_record;procedure set_doubles(p_index: Integer;
 p_double_record: t_double_record);
 
 
             function get_x(p_index: Integer): Double;procedure set_x(p_index: Integer; p_x: Double);
 
 
             function get_y(p_index: Integer): Double;procedure set_y(p_index: Integer; p_y: Double);
 
 
             function get_z(p_index: Integer): Double;procedure set_z(p_index: Integer; p_z: Double);
 public
 Constructor create;
 procedure add_doubles(p_double_record: t_double_record);
 
 
             procedure set_length(p_length: Integer);
               Destructor Destroy; Override;
 
             Property Doubles[p_index: Integer] : t_double_recordRead get_doubles Write set_doubles; Default;
 Property X[p_index: Integer] : Double
 Read get_x Write set_x;
 Property Y[p_index: Integer] : Double
 Read get_y Write set_y;
 Property Z[p_index: Integer] : Double
 Read get_z Write set_z;
 
 
             Property Count: Integer Read m_count Write m_count;end; // c_array_of_double
 
 
   function f_double_record(p_x, p_y, p_z: Double): t_double_record;
 |   et leur implémentation:     | function f_double_record(p_x, p_y, p_z: Double): t_double_record; begin
 Result.m_x:= p_x;
 Result.m_y:= p_y;
 Result.m_z:= p_z;
 end; // f_double_record
 
  // -- c_array_of_record_of_doubles
  Constructor c_array_of_record_of_doubles.create;begin
 InHerited Create;
 SetLength(m_array_of_double_record, k_granularity);
 end; // create
 
 
procedure c_array_of_record_of_doubles.add_doubles(p_double_record: t_double_record);begin
 if m_count>= Length(m_array_of_double_record)
 then SetLength(m_array_of_double_record, 2* Length(m_array_of_double_record));
 
      m_array_of_double_record[m_count]:= p_double_record;Inc(m_count);
 end; // add_double
 
 
function c_array_of_record_of_doubles.get_doubles(p_index: Integer): t_double_record;begin
 if p_index>= Length(m_array_of_double_record)
 then Raise Exception.Create('p_index> m_count');
 
      Result:= m_array_of_double_record[p_index];end; // get_doubles
 
 
procedure c_array_of_record_of_doubles.set_doubles(p_index: Integer; p_double_record: t_double_record);begin
 if p_index>= Length(m_array_of_double_record)
 then begin
 m_count:= p_index+ 1;
 SetLength(m_array_of_double_record, m_count);
 end;
 
 
    m_array_of_double_record[p_index]:= p_double_record;end; // set_doubles
 
 
function c_array_of_record_of_doubles.get_x(p_index: Integer): Double;begin
 Result:= Doubles[p_index].m_x;
 end; // get_x
 
 
procedure c_array_of_record_of_doubles.set_x(p_index: Integer; p_x: Double);begin
 if p_index>= Length(m_array_of_double_record)
 then begin
 m_count:= p_index+ 1;
 SetLength(m_array_of_double_record, m_count);
 end;
 
 
    m_array_of_double_record[p_index].m_x:= p_x;end; // set_x
 
  // -- ...ooo... idem for Y and Z
 
procedure c_array_of_record_of_doubles.set_length(p_length: Integer);begin
 m_array_of_double_record:= Nil;
 
 
    m_count:= p_length;SetLength(m_array_of_double_record, m_count);
 end; // set_length
 
 
Destructor c_array_of_record_of_doubles.destroy;begin
 m_array_of_double_record:= Nil;
 
      Inherited;end; // destroy
 
 |   et le projet Delphi de test:     | var g_c_array_of_record_of_doubles: c_array_of_record_of_doubles= Nil; 
 
procedure TForm1.create_arrayClick(Sender: TObject);begin
 g_c_array_of_record_of_doubles:= c_array_of_record_of_doubles.Create;
 end; // create_arrayClick
 
 
procedure TForm1.add_doublesClick(Sender: TObject);begin
 if g_c_array_of_record_of_doubles= Nil
 then g_c_array_of_record_of_doubles.Create;
 
 
    g_c_array_of_record_of_doubles.add_doubles(f_double_record(1.1, 2.2, 3.3));
 g_c_array_of_record_of_doubles
 .add_doubles(f_double_record(10.1, 20.2, 30.3));
 g_c_array_of_record_of_doubles
 .add_doubles(f_double_record(100.1, 200.2, 300.3));
 
 
    // -- not allowed// g_c_array_of_record_of_doubles.Doubles[3].m_x:= 3.14;
 g_c_array_of_record_of_doubles.Doubles[3]:= f_double_record(3.14, 0, 0);
 g_c_array_of_record_of_doubles.X[4]:= 6.28;
 end; // add_doubles_Click
 
  procedure TForm1.display_doublesClick(Sender: TObject);var l_index: Integer;
 begin
 for l_index:= 0 to g_c_array_of_record_of_doubles.Count- 1 do
 with g_c_array_of_record_of_doubles[l_index] do
 display(Format('x = %5.2f,   y =%5.1f,  z =%5.1f ', [m_x, m_y, m_z]));
 end; // display_doubles_Click
 
 
procedure TForm1.free_doubleClick(Sender: TObject);begin
 FreeAndNil(g_c_array_of_record_of_doubles);
 end; // free_double_Click
 
 |   dont voici l'image:    
 
 Notez que
  nous avons ajouté une FUNCTION qui convertit trois Doubles isolés en un RECORD
à notre grande surprise     | g_c_array_of_record_of_doubles.Doubles[3].m_x:= 3.14; 
 |   n'est pas autorisé
 
 Et pour la seconde solution
  voici la définition du RECORD:     | t_double_record= Record m_c_x_array, m_c_y_array, m_c_z_array: c_array_of_double_2;
 end; // t_double_record
 
 |  
et le projet Delphi de test:     | var g_c_record_of_array_of_doubles: t_double_record; 
 
procedure TForm1.create_arraysClick(Sender: TObject);begin
 with g_c_record_of_array_of_doubles do
 begin
 m_c_x_array:= c_array_of_double_2.Create;
 m_c_y_array:= c_array_of_double_2.Create;
 m_c_z_array:= c_array_of_double_2.Create;
 end; // with g_c_record_of_array_of_doubles
 end; // create_array_2Click
 
 
procedure TForm1.add_doubles_2Click(Sender: TObject);begin
 with g_c_record_of_array_of_doubles do
 begin
 m_c_x_array[0]:= 1.1;
 m_c_y_array[0]:= 2.2;
 m_c_z_array[0]:= 3.3;
 
 
      m_c_x_array[1]:= 10.1;m_c_y_array[1]:= 20.2;
 m_c_z_array[1]:= 30.3;
 end; // with g_c_record_of_array_of_doubles
 end; // add_double_property_Click
 
 
procedure TForm1.display_doubles_2Click(Sender: TObject);var l_index: Integer;
 begin
 with g_c_record_of_array_of_doubles do
 for l_index:= 0 to m_c_x_array.Count- 1 do
 display(Format('x= %5.1f,  y =%5.1f,  z =%5.1f ',
 [  m_c_x_array[l_index], m_c_y_array[l_index],
 m_c_z_array[l_index] ]));
 end; // display_double_property_Click
 
 
procedure TForm1.free_doubles_2Click(Sender: TObject);begin
 with g_c_record_of_array_of_doubles do
 begin
 FreeAndNil(m_c_x_array);
 FreeAndNil(m_c_y_array);
 FreeAndNil(m_c_z_array);
 end; // with g_c_record_of_array_of_doubles
 end; // free_double_2Click
 
 |   dont voici l'image:    
 
 Notez que
  dans la seconde solution, la définition est triviale, mais le code d'utilisation plus verbeux. Nous devrions en réalité utiliser un CLASS qui
encapsule les trois ARRAY OF Double. Donc une CLASS OF ARRAY OF Double
la seconde solution permettrait aussi d'accomoder des séries de taille
différentes. Supposons que nous souhaitions modéliser des nombres et de leur valeur absolue distinctes. Voici le schéma:   
 
 4.3 - tList of pt_record_of_doubleVoici le traitement du même problème utilisant des pointeurs:   
 Pour la première solution:
  voici les définitions:     | type t_measure= Record m_intensity, m_voltage, m_frequency: Double;
 end; // t_measure
 
 
     t_pt_measure= ^t_measure;
       c_tlist_of_pt_doubles=Class(tList)
 Private
 function get_measure(p_index: Integer): t_measure;
 procedure set_measure(p_index: Integer; p_measure: t_measure);
 
 
             function get_intensity(p_index: Integer): Double;procedure set_intensity(p_index: Integer; p_intensity: Double);
 Public
 Constructor create;
 procedure add_measure(p_measure: t_measure);
 Destructor Destroy; Override;
 
 
             Property Measure[p_index: Integer] : t_measureRead get_measure Write set_measure; Default;
 
 
             Property Intensity[p_index: Integer] : DoubleRead get_intensity Write set_intensity;
 end; // c_tlist_of_pt_doubles
 
 
function f_measure(p_intensity, p_voltage, p_frequency: Double): t_measure;
 |   et leur implémentation:     | function f_measure(p_intensity, p_voltage, p_frequency: Double): t_measure; begin
 Result.m_intensity:= p_intensity;
 Result.m_voltage:= p_voltage;
 Result.m_frequency:= p_frequency;
 end; // f_measure
 
  // -- c_tlist_of_pt_doubles
 
Constructor c_tlist_of_pt_doubles.create;begin
 Inherited Create;
 end; // create
 
 
procedure c_tlist_of_pt_doubles.add_measure(p_measure: t_measure);var l_pt_measure: t_pt_measure;
 begin
 New(l_pt_measure);
 l_pt_measure^:= p_measure;
 Inherited Add(l_pt_measure);
 end; // add_measure
 
 
function c_tlist_of_pt_doubles.get_measure(p_index: Integer): t_measure;var l_pt_measure: t_pt_measure;
 begin
 if p_index>= Count
 then Raise Exception.Create('p_index> m_count');
 
      Result:= t_pt_measure(Items[p_index])^;end; // get_measure
 
 
procedure c_tlist_of_pt_doubles.set_measure(p_index: Integer;p_measure: t_measure);
 var l_index: Integer;
 begin
 // -- if index beyond Count, create with 0 filled cells
 if p_index>= Count
 then
 For l_index:= Count to p_index do
 add_measure(f_measure(0, 0, 0));
 
 
    t_pt_measure(Items[p_index])^:= p_measure;end; // set_measure
 
 
function c_tlist_of_pt_doubles.get_intensity(p_index: Integer): Double;begin
 if p_index>= Count
 then Raise Exception.Create('p_index> m_count');
 
      Result:= t_pt_measure(Items[p_index])^.m_intensity;end; // get_intensity
 
 
procedure c_tlist_of_pt_doubles.set_intensity(p_index: Integer; p_intensity: Double);var l_index: Integer;
 begin
 // -- if index beyond Count, create with 0 filled cells
 if p_index>= Count
 then
 For l_index:= Count to p_index do
 add_measure(f_measure(0, 0, 0));
 
 
    t_pt_measure(Items[p_index])^.m_intensity:= p_intensity;end; // set_intensity
 
 
Destructor c_tlist_of_pt_doubles.destroy;var l_index: Integer;
 begin
 for l_index:= 0 To Count- 1 do
 Dispose(Items[l_index]);
 
      Inherited;end; // destroy
 
 |   ainsi que le projet Delphi de test:     | var g_c_tlist_of_pt_doubles: c_tlist_of_pt_doubles= Nil; 
 
procedure TForm1.create_listClick(Sender: TObject);begin
 g_c_tlist_of_pt_doubles:= c_tlist_of_pt_doubles.Create;
 end; // create_arrayClick
 
 
procedure TForm1.add_doublesClick(Sender: TObject);begin
 if g_c_tlist_of_pt_doubles= Nil
 then g_c_tlist_of_pt_doubles.Create;
 
 
    g_c_tlist_of_pt_doubles.add_measure(f_measure(1.1, 2.2, 3.3));g_c_tlist_of_pt_doubles.add_measure(f_measure(10.1, 20.2, 30.3));
 
 
    g_c_tlist_of_pt_doubles.Measure[2]:= f_measure(3.14, 0, 0);
 
    // -- ok if index< Count, but does not modify the value in the tListwith g_c_tlist_of_pt_doubles.Measure[2] do
 begin
 m_voltage:= 60.28;
 display(Format('i =%5.1f,  v =%5.1f,  f =%5.1f',
 [m_intensity, m_voltage, m_frequency]));
 display_line;
 end;
 
 
    g_c_tlist_of_pt_doubles.Intensity[3]:= 9.42;end; // add_doubles_Click
 
  procedure TForm1.display_doublesClick(Sender: TObject);var l_index: Integer;
 l_measure: t_measure;
 begin
 for l_index:= 0 to g_c_tlist_of_pt_doubles.Count- 1 do
 begin
 (*
 l_measure:= g_c_tlist_of_pt_doubles[l_index];
 with l_measure do
 display(Format('i =%5.1f,  v =%5.1f,  f =%5.1f',
 [m_intensity, m_voltage, m_frequency]));
 *)
 
      with g_c_tlist_of_pt_doubles[l_index] dodisplay(Format('i =%5.1f,  v =%5.1f,  f =%5.1f',
 [m_intensity, m_voltage, m_frequency]));
 end; // for l_index
 end; // display_doubles_Click
 
 
procedure TForm1.free_listClick(Sender: TObject);begin
 FreeAndNil(g_c_tlist_of_pt_doubles);
 end; // free_double_Click
 
 |   dont voici l'image:    
 
 Notez que
  le RECORD n'a pas besoin d'être pointé. Si vous devez passer le RECORD à une PROCEDURE vous pouvez utiliser un paramètres VAR ou CONST, si vous
souhaitez éviter la copie des 3 pointeurs sur la pile (3 dans notre cas, mais si vous utilisez plus de données pour chaque tuple, cela peut devenir plus volumineux).
comme précédemment nous n'avons pu accéder aux champs par la propriété
indexée Measure[], et WITH fonctionne en lecture, mais pas en écriture (il semble que nous modifions un RECORD local sur la pile, pas le RECORD de la tList)
 
 La seconde solution consiste simplement à utiliser le RECORD de liste pointées:
     | type t_measure= Record m_intensity_list, m_voltage_list,
 m_frequency: t_tlist_of_pt_double;
 end; // t_measure
 
 |  
ce qui est très similaire à la technique de RECORD of t_array_of_double   
 
 4.4 - tList OF c_doublesFinalement nous pouvons stocker les valeurs d'une même mesure dans une CLASSe, avec les deux structures suivantes:
  
 Voici un exemple de CLASS OF CLASS, où nous avons placé dans chaque cellule des données contenant des doubles et n'importe quelle autre type de données
(ici 2 Doubles et un Integer):
  voici les définitions pour notre gestion de séries boursières:     | type c_stock_value= Class
 m_opening_price, m_closing_price: Double;
 m_volume: Integer;
 Constructor create(p_opening_price, p_closing_price: Double;
 p_volume: Integer);
 end; // c_doubles
 
       c_tlist_of_c_doubles=Class(tList)
 Private
 function get_stock_value(p_index: Integer): c_stock_value;
 procedure set_stock_value(p_index: Integer;
 p_c_stock_value: c_stock_value);
 
 
             function get_opening_price(p_index: Integer): Double;procedure set_opening_price(p_index: Integer;
 p_opening_price: Double);
 Public
 Constructor create;
 procedure add_stock_value(p_c_stock_value: c_stock_value);
 Destructor Destroy; Override;
 
 
             Property StockValue[p_index: Integer] : c_stock_valueRead get_stock_value Write set_stock_value; Default;
 
 
             Property OpeningPrice[p_index: Integer] : DoubleRead get_opening_price Write set_opening_price;
 end; // c_tlist_of_c_doubles
 
 |   qui sont implémentées ainsi:     | // -- c_stock_value 
 
Constructor c_stock_value.create(p_opening_price, p_closing_price: Double;p_volume: Integer);
 begin
 Inherited Create;
 
      m_opening_price:= p_opening_price;m_closing_price:= p_closing_price;
 m_volume:= p_volume;
 end; // create
 
  // -- c_tlist_of_c_doubles.
 
Constructor c_tlist_of_c_doubles.create;begin
 Inherited Create;
 end; // create
 
 
procedure c_tlist_of_c_doubles.add_stock_value(p_c_stock_value: c_stock_value);begin
 Inherited Add(p_c_stock_value);
 end; // add_stock_value
 
 
function c_tlist_of_c_doubles.get_stock_value(p_index: Integer): c_stock_value;begin
 if p_index>= Count
 then Raise Exception.Create('p_index> m_count');
 
      Result:= c_stock_value(Items[p_index]);end; // get_stock_value
 
 
procedure c_tlist_of_c_doubles.set_stock_value(p_index: Integer; p_c_stock_value: c_stock_value);var l_index: Integer;
 begin
 // -- if index beyond Count, create with 0 filled cells
 if p_index>= Count
 then
 For l_index:= Count to p_index do
 add_stock_value(c_stock_value.create(0.0, 0.0, 0));
 
 
    // -- copy the valueswith c_stock_value(Items[p_index]) do
 begin
 m_opening_price:= p_c_stock_value.m_opening_price;
 m_closing_price:= p_c_stock_value.m_closing_price;
 m_volume:= p_c_stock_value.m_volume;
 end; // with c_stock_value()
 end; // set_stock_value
 
 
function c_tlist_of_c_doubles.get_opening_price(p_index: Integer): Double;begin
 if p_index>= Count
 then Raise Exception.Create('p_index> m_count');
 
      Result:= c_stock_value(Items[p_index]).m_opening_price;end; // get_opening_price
 
 
procedure c_tlist_of_c_doubles.set_opening_price(p_index: Integer; p_opening_price: Double);var l_index: Integer;
 begin
 // -- if index beyond Count, create with 0 filled cells
 if p_index>= Count
 then
 For l_index:= Count to p_index do
 add_stock_value(c_stock_value.create(0.0, 0.0, 0));
 
 
    // -- copy the valueswith c_stock_value(Items[p_index]) do
 m_opening_price:= p_opening_price;
 end; // set_opening_price
 
  Destructor c_tlist_of_c_doubles.destroy;var l_index: Integer;
 begin
 for l_index:= 0 To Count- 1 do
 c_stock_value(Items[l_index]).Free;
 
 
    Inherited;end; // destroy
 
 |   et voici un  projet Delphi de test:
    | var g_c_tlist_of_c_doubles: c_tlist_of_c_doubles= Nil; 
 
procedure TForm1.create_listClick(Sender: TObject);begin
 g_c_tlist_of_c_doubles:= c_tlist_of_c_doubles.Create;
 end; // create_arrayClick
 
 
procedure TForm1.add_doublesClick(Sender: TObject);begin
 if g_c_tlist_of_c_doubles= Nil
 then g_c_tlist_of_c_doubles.Create;
 
 
    g_c_tlist_of_c_doubles.add_stock_value(c_stock_value.create(1.1, 1.3, 200));
 g_c_tlist_of_c_doubles.add_stock_value(
 c_stock_value.create(5.6, 5.4, 400));
 
 
    // -- WITH tries to read beyond the end// with g_c_tlist_of_c_doubles.StockValue[2] do
 //  m_opening_price:= 10.11
 g_c_tlist_of_c_doubles.StockValue[2]:= c_stock_value.create(7.2, 7.8, 300);
 
 
    // -- once the cell exists, can modify itwith g_c_tlist_of_c_doubles.StockValue[2] do
 m_closing_price:= 77.8;
 
      g_c_tlist_of_c_doubles.OpeningPrice[2]:= 99.9;end; // add_doubles_Click
 
 
procedure TForm1.display_doublesClick(Sender: TObject);var l_index: Integer;
 begin
 for l_index:= 0 to g_c_tlist_of_c_doubles.Count- 1 do
 with g_c_tlist_of_c_doubles.StockValue[l_index] do
 display(Format('open=%5.2f close=%5.2f  vol=%5d',
 [m_opening_price, m_closing_price, m_volume]));
 end; // display_doubles_Click
 
 
procedure TForm1.free_listClick(Sender: TObject);begin
 FreeAndNil(g_c_tlist_of_c_doubles);
 end; // free_double_Click
 
 |   dont voici l'image:    
 
 La solution utilisant plusieurs tList de c_tList OF c_double serait définit par:
     | type t_stock_values= Record m_c_opening_price_list,
 m_c_closing_price_list: c_tList_of_c_double;
 m_c_volume_list: c_tList_of_c_integer;
 end; // t_stock_values
 
 |   
 Notez que:
  si nous avions des traitements distincts sur les listes de réels (pour les intensités, calculer la moyenne, pour les puissances la somme des carrés
etc), il la solution de droite serait la plus appropriée, alors que si tous les réels ont le même traitement, et que nous avons des traitements sur une mesure, la solution de gauche serait mieux adaptée
 
 
 
 5 - Télécharger le code source DelphiVous pouvez télécharger les différents projets: Ce .ZIP qui comprend:  
Ces .ZIP, pour les projets en Delphi 6, contiennent des chemins RELATIFS. Par conséquent:le .DPR, la forme principale, les formes annexes eventuelles
les fichiers de paramètres (le schéma et le batch de création)
dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonaume)
  Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.créez un répertoire n'importe où sur votre machine
placez le .ZIP dans ce répertoire
dézippez et les sous-répertoires nécessaires seront créés
compilez et exécutez
 
La notation utilisée est la notation alsacienne qui consiste à préfixer les identificateurs par la zone de compilation: K_onstant, T_ype, G_lobal,
L_ocal, P_arametre, F_unction, C_lasse. Elle est présentée plus en détail dans l'article La
Notation Alsacienne
  
 Comme d'habitude:
  nous vous remercions de nous signaler toute erreur, inexactitude ou
problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :   et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos
blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.
 
 
 
 6 - RéférencesNous avons déjà présenté des techniques similaires. En particulier 
Ces techniques sont naturellement abordées dans nos formations sur les techniques de programmation objet, et en particulier
 
 
 7 - L'auteurJohn COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets  (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le
conseil (composants, architecture, test) et la
formation. Son site contient des articles
avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et
UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client.
 |