FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 119, nombre de questions : 909, dernière mise à jour : 22 décembre 2016  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).

Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.

L'équipe Delphi de Developpez.com.

Commentez


SommaireLangageTypes de données (34)
précédent sommaire suivant
 

L'opérateur @ permet d'obtenir l'adresse de l'objet.

Il suffit de transtyper l'adresse en Cardinal pour afficher le résultat en hexadécimal :

Code delphi : Sélectionner tout
IntToHex(Cardinal(@MonObjet),6);

Mis à jour le 17 octobre 2013 Smortex

La notion de base de pointeur est assez simple : il s'agit d'une variable qui stocke l'emplacement en mémoire d'un autre élément (qui est le plus souvent une variable).

La mémoire :

Tout d'abord, la mémoire de l'ordinateur peut être représentée comme un nombre très important de cases d'une certaine
taille que l'on appelle un octet. Ces cases, pour que l'ordinateur puisse y accéder, sont repérées par un numéro : leur Adresse.
La mémoire d'un ordinateur est donc en quelque sorte un grand tableau de cases numérotées, ces cases contenant chacune un octet.

Les variables :

Le tableau qu'est la mémoire est rempli par des données qui, parfois, ont besoin d'un octet, de deux, de quatre ou plus, pour pouvoir être représentées : ces données sont appelées variables. Elles peuvent être des caractères, des nombres…
Imaginons une variable déclarée dans un code delphi :

Code Delphi : Sélectionner tout
var UnNombre: Cardinal;
UnNombre, qui a besoin de 32 bits pour être stocké, va donc utiliser en mémoire quatre cases contiguës (quatre octets).
Par exemple, les cases n°205, 206, 207 et 208.
Pour obtenir le numéro de la case (donc l'adresse) dans lequel elle se trouve, il existe deux possibilités : @UnNombre ou bien Addr(UnNombre).
L'adresse de UnNombre sera le numéro de la première case qu'il occupe, c'est-à-dire 205.

Exemple :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
var UneAdresse: Pointer;  
      UnNombre: Cardinal;  
begin  
  UneAdresse := @UnNombre;  
  //ou bien  
  UneAdresse := Addr(UnNombre);  
end;

Donc, @X signifie Donne-moi l'adresse de X.

Les pointeurs :

Premièrement, un pointeur est une variable, un peu similaire à un entier (c'est criant en C++, mais pas en Delphi). C'est une variable, sur 32 bits (4 octets), qui contient l'adresse d'une case de la mémoire.
Comme c'est similaire à un nombre entier, on peut tout-à-fait imaginer (pour l'instant, on ne fait qu'imaginer !) des
additions et des soustractions et même afficher son contenu (ça marche très bien en c++, mais pas en Delphi, qui "protège" ce genre de choses pour éviter des "accidents").
On dit qu'un pointeur, qui contient en général l'adresse d'une autre variable, "pointe" sur cette autre variable.
Quand la valeur de l'adresse contenue dans le pointeur est égale à zéro, alors ça se traduit en Delphi par UnPointeur = nil.
Maintenant, il peut être intéressant, connaissant une adresse, de pouvoir accéder à son contenu.
En supposant que UnPointeur = 205, UnPointeur^ nous donnera le contenu de ce qui se trouve à la case n°205, c'est-à-dire la valeur de UnNombre.
Donc, X^ signifie Donne-moi la valeur de ce qui se trouve en X.

Variables avancées :

Normalement, une variable d'un certain type (un byte, par exemple, qui prend un octet, donc une case), ne peut cohabiter avec une variable d'un autre type (un char, qui tient lui aussi sur un octet).
Cela peut pourtant être pratique pour transformer, sans faire de calcul, une variable UnByte contenant 65, directement en caractère UnChar qui vaudrait 'A'.
Delphi le permet, tout comme le C++ le permet avec son instruction Union.
La méthode, mal expliquée dans l'aide Delphi, est de déclarer un enregistrement avec une partie variable, comme ceci :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
  
Type  
  TSuperVariable = Record  
    Case b: Boolean of  
    True: (UnByte: Byte);  
    False: (UneChar: Char);  
  end;

Ensuite, on peut travailler "avec la mémoire" comme suit :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
var  
  SuperVariable: TSuperVariable  
  UnMessage: String;  
begin  
  SuperVariable.AByte := 65;  
  //est équivalent à  
  //SuperVariable.AChar := 'A';  
  
  UnMessage := 'Valeur de AByte au format caractère : ' + SuperVariable.AChar);  
  ShowMessage(UnMessage);  
end;

Rien n'empêche de faire des SuperVariables plus complexes, comme ceci :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
Type  
  TSuperVariable1 = Record  
    Case i: SmallInt of  
      1: (UnPetitReel: Single);  
      2: (UnEntierSigne: Integer);  
      3: (UnEntierNonSigne: Cardinal);  
      4: (UnPointeur: Pointer);  
      5: (UnPointeurSurUnEntier: ^Integer);  
  end;

On remarquera juste que les cinq types (Single, Integer, Cardinal, Pointer, ^Integer), proposent tous des variables de 4 octets. De là, les possibilités sont multiples (et dangereuses, donc attention…).

Addition et soustraction sur des pointeurs :

Pour ce qui est des additions et soustractions avec des pointeurs, c'est possible en déclarant un enregistrement avec une partie variable :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Type  
  TAccesMemoire = Record  
    Case i: Smallint of  
      1: (UnPointeur: Pointer);  
      2: (UneAdresse: Cardinal);  
      3: (UnPointeurSurCaractere: ^Char);  
      4: (UnPointeurSurByte: ^Byte);  
  end;  
  
var Acces: TAccesMemoire;  
    UneChaine: String;  
    i: Integer;  
    UnMessageBizarre: String;  
begin  
  //Initialisation des données  
  UneChaine := 'bonjour les Delphinautes, comment ça va ? :)';  
  i := 66;  
  UnMessageBizarre := '';  
  
  //on se place, sur le premier caractère de la chaîne :  
  Acces.UnPointeurSurCharactère := @UneChaine[1];  
  
  //on remplace le b minuscule par l'équivalent ASCII de ce qu'il y a dans i;  
  Acces.UnPointeurSurByte^ := i;  
  
  //Affichage  
  ShowMessage(UneChaine);  
  
  //deux pas en avant, un pas en arrière… (5 fois)   
  for i := 1 to 5 do  
  begin  
    //2 pas en avant  
    Acces.UneAdresse := Acces.UneAdresse + 2;  
    //on récupère le caractère pointé  
    UnMessageBizarre := UnMessageBizarre + Acces.UnPointeurSurCaractere^;  
    //1 pas en arrière  
    Acces.UneAdresse := Acces.UneAdresse-1;  
    //on récupère le caractère pointé  
    UnMessageBizarre := UnMessageBizarre + Acces.UnPointeurSurCaractere^;  
  end;  
  
  ShowMessage(UnMessageBizarre);  
  
end;

Mis à jour le 19 octobre 2013 LadyWasky Laurent Dardenne

Guide Pascal et Delphi, par Frédéric Beaulieu

Dans le menu Outils | Options du débogueur, sélectionnez l'onglet Exceptions du langage, puis dans la liste Type d'exceptions à ignorer désactiver la ou les exceptions que vous souhaitez ignorer lors d'une phase de débogage.

Décochez la case Arrêter sur les exceptions Delphi si vous voulez que le débogueur interrompe l'exécution de votre programme lorsque celui-ci déclenche une exception Delphi.

Mis à jour le 19 janvier 2014 Laurent Dardenne

Vous trouverez, sur les URL suivantes, des tutoriels sur la gestion des exceptions :

Mis à jour le 19 janvier 2014 Laurent Dardenne

Lorsqu'un tableau dynamique a besoin d'être redimensionné de manière fréquente (par exemple, dans une boucle), il vaut mieux effectuer cette opération de manière « intelligente » pour gagner du temps et éviter de fragmenter la mémoire.

Voilà un code qui récupère tous les handles des composants du projet de type TWinControl pour les placer dans un tableau dynamique :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure TForm1.Button1Click(Sender: TObject); 
var 
  LArray: array of HWND; 
  I: Integer; 
begin 
  SetLength(LArray, 0); 
  for I := 0 to Pred(ComponentCount) do 
    if Components[I] is TWinControl then 
    begin 
      SetLength(LArray, Length(LArray) + 1); 
      LArray[Length(LArray) + 1] := TWinControl(Components[I]).Handle; 
    end; 
end;
Le motif suivant est utilisé classiquement par beaucoup de programmeurs pour étendre la taille du tableau et affecter une valeur au nouvel élément réservé :
Code delphi : Sélectionner tout
1
2
SetLength(LArray, Length(LArray) + 1); 
      LArray[Length(LArray) + 1] := TWinControl(Components[I]).Handle;
Ce n'est pas la meilleure manière de procéder, car à chaque tour de boucle il y a réservation d'un nouveau petit bout de mémoire. De manière répétée, cela rend votre code lent et fragmente la mémoire de votre application.

Pour y remédier, il vaut mieux lorsqu'on connaît la taille que prendra le tableau, effectuer l'allocation une seule fois en début de boucle :
Code delphi : Sélectionner tout
1
2
3
4
L := MyList.Count() ; 
SetLength(LArray, L) ; 
For I := 0 to Pred(L) do 
  LArray[I] := ...
Lorsque qu'on connaît la taille maximale que peut prendre le tableau, il vaut mieux le dimensionner à cette taille quitte à la diminuer au besoin. Dans notre premier exemple, cela conduirait à supposer que tous les composants pourraient être des TWinControl, donc à dimensionner notre tableau à ComponentCount. On utilise alors une variable supplémentaire pour compter le nombre d'éléments réellement ajoutés et redimensionner le tableau en fin de boucle (en effet, on ne peut utiliser la variable qui sert d'index de boucle car Delphi la laisse dans un état indéterminé) :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
procedure TForm1.Button1Click(Sender: TObject); 
var 
  LArray: array of HWND; 
  I, J: Integer; 
begin 
  J := 0; 
  SetLength(LArray, ComponentCount); 
  for I := 0 to Pred(ComponentCount) do 
    if Components[I] is TWinControl then 
    begin 
      LArray[I] := TWinControl(Components[I]).Handle; 
      Inc(J); 
    end; 
  SetLength(LArray, J); 
end;
Enfin, lorsqu'on ne connaît pas la taille maximale que peut prendre un tableau (on a par exemple une boucle While sans maximum fixé), on peut enfin allouer par « blocs » d'éléments. Autrement dit, on fixe une constante définissant un nombre d'éléments à allouer par cycle d'allocations. Tant que la taille actuelle est inférieure au nombre d'éléments actuellement alloués, on ne fait rien ; et dès que celle-ci la dépasse, on alloue un nouveau bloc. Il va de soi que la taille des blocs d'allocation est proportionnelle au nombre de résultats qui sont censés être délivrés par la boucle : si par exemple il est plausible que la boucle renvoie 5000 éléments à affecter, on peut avancer par blocs de 500 ou 1000 éléments. Enfin, comme le nombre total d'éléments affectés ne correspondra pas forcément à la dimension allouée au tableau on utilise comme la dernière méthode une variable incrémentée à chaque affectation pour rétablir la taille du tableau exacte en fin de boucle :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
procedure TFoo.Bar 
const 
  cstGrowBy: Integer = 100; 
var 
  LList: array of Int64; 
  I, J: Integer; 
begin 
  SetLength(LList, 0); 
  I := 0; 
  AcquireDriver; 
  try 
    SetSQL('SELECT ID FROM ...); //Requête SQL donnant un nombre N de résultats             
    ExecSelect; 
    while not QueryEOF do //Notre boucle 
    try 
      //Motif d'allocation évoqué dans le paragraphe ci dessus 
      if (I + 1 > Length(LList)) then //Si le nombre actuel d'éléments atteint la taille actuelle 
        SetLength(LList, Length(LList) + cstGrowBy); //On alloue un nouveau bloc 
      LList[I] := GetFieldAsInt64('ID'); //On affecte une valeur au tableau 
    finally 
      Inc(I); 
      QueryNext; 
    end; 
SetLength(LList, I) ; 
//On peut exploiter le tableau...

Mis à jour le 19 janvier 2014 Reisubar

Cette approche n'est possible qu'à partir de Delphi 2005.

Lors de la construction d'un objet de la manière suivante :

Code delphi : Sélectionner tout
1
2
3
4
with TMOnObjet.Create do  
begin  
  
end;
Il est parfois utile de récupérer la référence de l'objet pour la communiquer à un traitement.
Sous Delphi 2005 l'utilisation de Class Helper peut être une solution.
Code delphi : Sélectionner tout
1
2
3
4
5
Type  
  GetterClassHelper=Class Helper For TObject  
    Function WriteClassName:ShortString;  
    Function  GetInstance:TObject;  
  end;
L'appel devenant
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
begin  
 With TStringList.Create do  
  begin  
   ...  
   Traitement(GetInstance); // récupére une référence sur l'instance  
   ...  
  end;  
end.
Il est possible d'utiliser une variable locale en lieu et place de cette mécanique basée sur les Class Helper.

PS : Sous Delphi 2005 cette évolution du langage n'est pas documentée pour Win32 mais l'est pour Delphi .NET.
Sous Delphi 2006 les assistants de classe sont bien implémentés.

Voici un programme illustrant son utilisation:
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
program classhelper;  
  
{$APPTYPE CONSOLE}  
  
uses  
  SysUtils;  
  
Type  
  TTest=Class  
   Nom: String;  
  end;  
  
  GetterClassHelper=Class Helper For TObject  
    Function WriteClassName:ShortString;  
    Function  GetInstance:TObject;  
  end;  
  
  Function GetterClassHelper.WriteClassName:ShortString;  
   begin  
      // Self fait référence au type Test, et non à GetterClassHelper.  
     Result:=Self.ClassName;  
   end;  
  
   function GetterClassHelper.GetInstance:TObject;  
   begin  
     // Self fait référence à la variable en cours,  
     // et non à une possible instance de type GetterClassHelper.  
    Result:=Self;  
   end;  
  
Procedure Visualise(AInstance :TObject; NomVaraible:String);  
begin  
 Writeln('Nom de la variable : ',NomVaraible);  
 Writeln;  
 Writeln('Instance de la classe '+ TTest(AInstance).WriteClassName+' dans la methode visualise : '+TTest(AInstance).Nom);  
 Writeln;  
end;  
  
Var Premier, Second : TTest;  
  
begin  
 Premier:=TTest.Create;  
 Premier.Nom:='Je reference l''instance Premier';  
 visualise(Premier,'Premier');  
  
  // Teste si on récupére bien une référence sur l'instance Premier  
  // équivaut à :  
  //  Second:=Premier  
 Second:=TTest(Premier.GetInstance);  
 visualise(Second,'Second');  
 Readln;  
  
 Premier.Free;  
 Second:=Nil;  
  
// Objectif final  
  With TTest.Create do  
  Try  
   Nom:='Je reference l''instance transitoire dans le bloc With-do';  
   visualise(GetInstance,' ici elle n''a pas de nom');  
  Finally  
   Free;  
  end;   
 Readln; 
end.
Dans notre exemple le code suivant ne pourra pas compiler car Self n'a pas d'existence dans ce programme console :
Code delphi : Sélectionner tout
1
2
3
4
5
With TTest.Create do  
  begin  
   Nom:='Je reference l''instance transitoire dans le bloc With-do';  
   visualise(self,' Dans notre cas self n''existe pas');  
  end;
Si dans une méthode d'une classe on utilise le mot clé self dans le bloc With do begin end, self fera référence à l'instance courante de la classe comportant la méthode en cours d'exécution, et non à l'instance de l'objet créé à la volée dans le bloc with.

Mis à jour le 19 janvier 2014 Laurent Dardenne

Le transtypage est trop souvent confondu avec l'opérateur as. Régulièrement, on utilise l'un ou l'autre sans trop y faire attention.
Pourtant, chacun a son utilisation propre.

Le transtypage

Pour commencer, le transtypage (du latin trans : à travers), c'est simplement considérer une valeur d'un type donné comme une valeur d'un autre type. La seule contrainte est que ces deux types soient stockés sur le même nombre d'octets en mémoire. Ainsi, n'importe quel TObject peut être transtypé en Single et vice versa, car ils sont tous deux stockés sur 4 octets ; par contre, un TObject ne peut être transtypé en Double (il y aura transtypage incorrect), car Double est stocké sur 8 octets.

Dans le code exécutable produit par le compilateur, il n'y a aucune différence entre une affectation d'un Single à un autre et l'affectation d'un TObject transtypé en Single à un Single. Plus exactement, il n'y a aucune différence entre un Single et un TObject transtypé en Single, tout simplement.
Le seul effet du transtypage est d'empêcher le compilateur de signaler une erreur d'incompatibilité de types.

NB : il possible de "transtyper" un integer en un Byte, ou même un TObject en un Char, alors qu'ils ne sont pas stockés sur le même nombre d'octets. En réalité, ce n'est pas un réel transtypage : les transtypages entre types scalaires entiers (entiers, pointeurs, objets et caractères), ou entre nombres (entiers et floats), de même que les transtypages entre types chaînes, sont compilés spécialement de façon à effectuer une véritable conversion de format. N'oubliez pas que dans le cas où un pointeur est impliqué, cette conversion n'a toutefois aucun sens.

L'opérateur as avec des classes

D'autre part, l'opérateur as. Celui-ci fonctionne différemment selon qu'il est utilisé avec des classes ou des interfaces.

Dans le cas des classes, l'opérateur [as] n'est pas différent du transtypage, il ajoute simplement un test pour vérifier si ce transtypage est valide. Ce test est effectué à l'aide de l'opérateur is. Puis, si le transtypage est valide, il est appliqué, sinon une exception EInvalidCast est générée.

En fait, le code suivant :

Code delphi : Sélectionner tout
ClasseEnfant := ClasseParent as TClasseEnfant;
correspond à celui-ci :
Code delphi : Sélectionner tout
1
2
3
4
if ClasseParent is TClasseEnfant then 
  ClasseEnfant := TClasseEnfant(ClasseParent) 
else 
  EInvalidCast.Create(ClasseParent.ClassName + ' n''est pas un descendant de '+TClasseEnfant.ClassName);
Autrement dit, lorsque vous savez que ClasseParent est bel et bien une instance de TClasseEnfant, utilisez le transtypage ; cela vous évitera des tests inutiles et donc une perte de temps à l'exécution. D'autant plus que l'opérateur is doit parcourir dynamiquement la hiérarchie de la classe pour déterminer son résultat. Si, en revanche, vous devez vérifier que les classes sont compatibles, utilisez soit l'opérateur is et un transtypage ou l'opérateur as.

Notez aussi que l'opérateur as, avec des classes, peut être utilisé uniquement si ClasseParent est déclarée comme une classe dans la généalogie directe de TClasseEnfant. Par généalogie directe, j'entends les parents, grands-parents, enfants, petits-enfants etc. Mais pas les cousins ou les oncles par exemple…

Utiliser is ou as ?

L'utilisation de l'un ou l'autre amène à des modèles de programmation différents. Avec l'opérateur is, vous devrez utiliser des tests de type if. Avec l'opérateur as, vous devrez encadrer votre code de blocs try et gérer les exceptions qui peuvent être générées.
Dans le cas contraire, vous vous exposez à des risques de plantage brutal de votre programme.

L'opérateur as avec des interfaces

Finalement, l'opérateur as, utilisé avec les interfaces, est l'appel de la méthode QueryInterface avec génération
d'une exception EIntfCastError si la référence ne supporte pas l'interface demandée.

Ainsi, le code suivant :
Code delphi : Sélectionner tout
UneInterface := UneAutreInterface as IUneInterface;
équivaut à celui-là :
Code delphi : Sélectionner tout
1
2
if UneAutreInterface.QueryInterface(GUID_de_IUneInterface, UneInterface) <> 0 then 
  raise EIntfCastError.Create('La référence n''implémente pas l'interface demandée');
Remarquez que ce test requiert que l'interface IUneInterface ait été gratifiée d'un GUID… Si ce n'est pas le cas, il y aura erreur de compilation.

Contrairement à l'utilisation sur ces classes, l'opérateur as appliqué à des interfaces ne demande pas des interfaces de la même branche généalogique. C'est normal, c'est la philosophie des interfaces : un objet peut implémenter deux interfaces n'ayant aucun rapport l'une avec l'autre.

À propos du portage sous Delphi .NET

Si votre code est destiné à être porté sous .NET, n'utilisez plus de transtypages dits sauvages, tel que integer(UnObjet), car ils ne sont pas autorisés en .NET. Utilisez à la place l'opérateur as.

Mis à jour le 19 janvier 2014 sjrd

Avec Delphi 2009 et l'apparition des types génériques (classe ou enregistrement), il faut bien sûr pouvoir avoir des informations sur les types.

Delphi nous fournit donc quelques fonctions utiles par le biais de quelques unités :

  • Genericfaults.Des ;
  • TypInfo ;
  • IntfInfo.

Les fonctions :
  • SizeOf : vous la connaissez sûrement, elle permet de récupérer la taille en octets d'un type.
  • TypeInfo : permet de récupérer des informations sur le type (type entier, flottant, ordinal, enregistrement, classe, interface...) ;
  • GetTypeData : permet de récupérer des informations sur la donnée du type (type byte, word, single, char, string, widechar...) ;
  • GetTypeName : permet de récupérer le nom du type (integer, byte, string...) ;
  • Default : met la donnée à sa valeur nulle (zero, nil).

Mise en place : au moment de la déclaration de votre classe ou record générique, vous pouvez imaginer cette déclaration :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type 
  TGenericPoint<T> = record 
  public 
    X, Y : T; 
  public 
    function _Size: integer; // renvois la taille du type T 
    function _Info: pTypeInfo; // renvois les infos du type T 
    function _Data: pTypeData; // renvois les infos de la données du type T 
    function _Name: string; // renvois le nom du type T 
    procedure _Zero; // mets à zéro X et Y peu importe le type de T 
  end; 
  
  TSmallPoint = TGenericPoint<SmallInt>; 
  TPoint = TGenericPoint<Integer>;  
  TPointF = TGenericPoint<Single>; 
  TBigPoint = TGenericPoint<Int64>; 
  TBigPointF =  TGenericPoint<Double>;
Voilà pour l'interface, voyons l'implémentation :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function TGenericPoint<T>._Name: string; 
begin 
  result := GetTypeName(TypeInfo(T)); 
end; 
  
function TGenericPoint<T>._Size: integer; 
begin 
  result := SizeOf(T) shl 1; 
end; 
  
function TGenericPoint<T>._Info: pTypeInfo; 
begin 
  result := pTypeInfo(TypeInfo(T)); 
end; 
  
function TGenericPoint<T>._Data: pTypeData; 
begin 
  result := pTypeData(GetTypeData(_Info)); 
end; 
  
procedure TGenericPoint<T>._Zero; 
begin 
  X := Default(T); 
  Y := Default(T); 
end;

Mis à jour le 10 avril 2014 Dr.Who

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Responsables bénévoles de la rubrique Delphi : Gilles Vasseur - Alcatîz -