Les Methodes DELPHI

Une méthode est une procédure ou une fonction associée à une classe. Un appel de méthode spécifie l'objet (ou la classe si c'est une méthode de classe) sur lequel la méthode agit. Par exemple, SomeObject.Free appelle la méthode Free de SomeObject.

Cette rubrique couvre les sujets suivants :

  • Déclarations et implémentations de méthodes
  • Liaison de méthodes
  • Surcharge de méthodes
  • Constructeurs et destructeurs
  • Méthodes de messages

A propos des méthodes

Au sein d'une déclaration de classe, les méthodes apparaissent comme des en-têtes de procédures ou de fonctions qui fonctionnent comme les déclarations forward. Quelque part après la déclaration de classe, mais à l'intérieur du même module, chaque méthode doit être implémentée par une déclaration de définition. Si; par exemple, la déclaration de TMyClass contient une méthode appelée DoSomething :

 type
    TMyClass = class(TObject)
       ...
       procedure DoSomething;
       ...
    end;

Une déclaration de définition pour DoSomething doit apparaître plus loin dans le module :

 procedure TMyClass.DoSomething;
 begin
      ...
 end;

Si une classe peut être déclarée dans la section interface ou la section implementation d'une unité, les déclarations de définition des méthodes de classe doivent se trouver dans la section implementation.

Dans l'en-tête d'une déclaration de définition, le nom de la méthode est toujours qualifié par le nom de la classe à laquelle elle appartient. L'en-tête peut répéter la liste de paramètres depuis la déclaration de classe ; si c'est le cas, l'ordre, le type et le nom des paramètres doivent correspondre exactement et, si la méthode est une fonction, la valeur de retour doit aussi correspondre.

Les déclarations des méthodes peuvent inclure des directives spéciales qui ne sont pas utilisées par d'autres fonctions ou procédures. Les directives doivent apparaître uniquement dans la déclaration de classe et pas dans la déclaration de définition, et doivent toujours être dans l'ordre suivant :

reintroduce; overload; liaison; convention d'appel; abstract; avertissement

Où :

  • liaison correspond à virtual, dynamic ou override ;
  • convention d'appel correspond à register, pascal, cdecl, stdcall, or safecall;
  • avertissement correspond à platform, deprecated ou library. Pour plus d'informations sur ces directives d'avertissement (de conseil), voir Directives de conseil.

Toutes les directives Delphi sont listées dans Directives.

Inherited

Le mot réservé inherited joue un rôle particulier dans l'implémentation de comportements polymorphiques. Il peut apparaître dans une définition de méthode avec ou sans identificateur à la suite.

Si inherited est suivi par le nom d'un membre, il représente un appel de méthode normal ou une référence à une propriété ou à un champ, sauf que la recherche du membre référencé commence avec l'ancêtre immédiat de la classe de la méthode englobante. Par exemple, quand l'instruction :

 inherited Create(...);

apparaît dans la définition d'une méthode, elle appelle la méthode Create héritée.

Quand inherited est utilisé sans être suivi d'un identificateur, il désigne la méthode héritée portant le même nom que la méthode en cours ou, si la méthode en cours est un gestionnaire de message, le gestionnaire de message hérité pour le même message. Dans ce cas, inherited ne prend pas de paramètres explicites, mais transmet à la méthode héritée les paramètres utilisés pour l'appel de la méthode englobante. Par exemple :

 inherited;

apparaît fréquemment dans l'implémentation des constructeurs. Cette instruction appelle le constructeur hérité avec les mêmes paramètres que ceux transmis au descendant.

Self

Au sein de l'implémentation d'une méthode, l'identificateur Self référence l'objet dans lequel la méthode est appelée. Voici, par exemple, l'implémentation de la méthode Add de TCollection dans l'unité Classes :

 function TCollection.Add: TCollectionItem;
 begin
     Result := FItemClass.Create(Self);
 end;

La méthode Add appelle la méthode Create de la classe référencée par le champ FItemClass, qui est toujours un descendant de TCollectionItem. TCollectionItem.Create ne prend qu'un seul paramètre de type TCollection, donc Add le transmet à l'objet instance de TCollection où Add est appelée. Cela est illustré dans le code suivant :

 var MyCollection: TCollection;
     ...
     MyCollection.Add   // MyCollection is passed to the 
                        // TCollectionItem.Create method

Self est utile pour diverses raisons. Par exemple, un identificateur de membre déclaré dans un type classe peut être redéclaré dans le bloc de l'une des méthodes de la classe. Dans ce cas, vous pouvez accéder à l'identificateur du membre d'origine en utilisant Self.Identifier.

Pour plus d'informations sur Self dans les méthodes de classe, voir "Opérateurs de classes" dans Références de classes.

Liaison de méthode

Les liaisons de méthodes peuvent être statiques (par défaut), virtuelles ou dynamiques. Les méthodes virtuelles et dynamiques peuvent être redéfinies et elles peuvent être abstraites. Ces désignations jouent un rôle quand une variable d'un type classe contient une valeur d'un type classe descendant. Elles déterminent quelle implémentation est activée lors de l'appel d'une méthode.

Méthodes statiques

Par défaut les méthodes sont statiques. Quand une méthode statique est appelée, le type déclaré (à la compilation) de la variable classe ou objet utilisé dans l'appel de la méthode détermine l'implémentation à activer. Dans l'exemple suivant, les méthodes Draw sont statiques :

 type
     TFigure = class
       procedure Draw;
     end;
 
     TRectangle = class(TFigure)
       procedure Draw;
     end;

Etant donné ces déclarations, le code suivant illustre l'effet de l'appel d'une méthode statique. Dans le second appel à Figure.Draw, la variable Figure référence un objet de classe TRectangle, mais l'appel invoque l'implémentation de Draw dans TFigure, car le type déclaré de la variable Figure est TFigure :

 var
     Figure: TFigure;
     Rectangle: TRectangle;
 
     begin
             Figure := TFigure.Create;
             Figure.Draw;              // calls TFigure.Draw
             Figure.Destroy;
             Figure := TRectangle.Create;
             Figure.Draw;              // calls TFigure.Draw
 
             TRectangle(Figure).Draw;  // calls TRectangle.Draw
 
             Figure.Destroy;
             Rectangle := TRectangle.Create;
             Rectangle.Draw;          // calls TRectangle.Draw
             Rectangle.Destroy;
     end;

Méthodes virtuelles et dynamiques

Pour rendre une méthode virtuelle ou dynamique, incluez la directive virtual ou dynamic dans sa déclaration. Les méthodes dynamiques et virtuelles, à la différence des méthodes statiques, peuvent être redéfinies dans les classes descendantes. Quand une méthode redéfinie est appelée, le type réel (à l'exécution) de la classe ou de l'objet utilisé dans l'appel de la méthode, et non pas le type déclaré de la variable, détermine l'implémentation à activer.

Pour redéfinir une méthode, redéclarez-la avec la directive override. Une déclaration override doit correspondre à la déclaration de l'ancêtre dans l'ordre et le type de ses paramètres, ainsi que dans son type de résultat (le cas échéant).

Dans l'exemple suivant, la méthode Draw déclarée dans TFigure est redéfinie dans deux classes descendantes :

 type
     TFigure = class
       procedure Draw; virtual;
     end;
 
     TRectangle = class(TFigure)
       procedure Draw; override;
     end;
 
     TEllipse = class(TFigure)
       procedure Draw; override;
     end;

Etant donné ces déclarations, le code suivant illustre l'effet de l'appel d'une méthode virtuelle via une variable dont le type réel change à l'exécution :

 var
    Figure: TFigure;
 
    begin
      Figure := TRectangle.Create;
      Figure.Draw;      // calls TRectangle.Draw
      Figure.Destroy;
      Figure := TEllipse.Create;
      Figure.Draw;      // calls TEllipse.Draw
      Figure.Destroy;
    end;

Seules les méthodes virtuelles et dynamiques peuvent être redéfinies. Par contre, toutes les méthodes peuvent être surchargées ;

Méthodes finales

Le compilateur Delphi prend aussi en charge le concept de méthodes virtuelles et dynamiques finales. Les déclarations des méthodes finales ont la forme suivante :

function|procedure FunctionName; virtual|dynamic; final; 

Ici, la syntaxe virtual|dynamic (deux mots clé et le symbole | entre les mots clés) est utilisée pour spécifier qu'un seul des mots clés virtual ou dynamic doit être utilisé. Seul le mot clé virtual ou dynamic n'a de sens; le symbole de tuyau lui-même doit être supprimé.

Seul le mot clé final est appliqué à une méthode virtuelle ou dynamique, aucune classe descendante ne peut redéfinir cette methode. L'usage du mot clé final est une décision de conception importante qui permet de définir l'utilisation de la classe. Il peut aussi donner au compilateur des conseils lui permettant d'optimiser le code produit.

Remarque : Les mots clés virtual ou dynamic doivent être écrits avant le mot clé final.

Exemple

type
  Base = class
    procedure TestProcedure; virtual;
    procedure TestFinalProcedure; virtual; final;
  end;

  Derived = class(Base)
    procedure TestProcedure; override;
       //Ill-formed: E2352 Cannot override a final method
    procedure TestFinalProcedure; override;
  end;

Comparaison des méthodes virtuelles et des méthodes dynamiques

Dans Delphi pour Win32, d'un point de vue sémantique, les méthodes virtuelles et les méthodes dynamiques sont équivalentes. Toutefois, elles diffèrent dans l'implémentation de la répartition de l'appel de méthode à l'exécution : les méthodes virtuelles optimisent la rapidité alors que les méthodes dynamiques optimisent la taille du code.

En général, les méthodes virtuelles constituent la manière la plus efficace d'implémenter un comportement polymorphique. Les méthodes dynamiques sont utiles quand une classe de base déclare de nombreuses méthodes pouvant être redéfinies qui sont héritées par de nombreuses classes descendantes d'une application, mais rarement redéfinies.

Remarque : N'utilisez les méthodes dynamiques que s'il existe un avantage clair et visible de le faire. Utilisez habituellement les méthodes virtuelles.

Redéfinition ou dissimulation

Si une déclaration de méthode spécifie le même identificateur de méthode et la même signature de paramètre qu'une méthode héritée, sans spécifier override, la nouvelle déclaration masque ou dissimule simplement la méthode héritée sans la redéfinir. Les deux méthodes existent alors dans la classe descendante, où le nom de méthode est lié statiquement. Par exemple :

 type
    T1 = class(TObject)
       procedure Act; virtual;
    end;
 
    T2 = class(T1)
       procedure Act;   // Act is redeclared, but not overridden
    end;
 
 var
    SomeObject: T1;
 
 begin
    SomeObject := T2.Create;
    SomeObject.Act;    // calls T1.Act
 end;

Reintroduce

La directive reintroduce supprime les avertissements du compilateur informant qu'une méthode virtuelle précédemment déclarée est masquée. Par exemple :

 procedure DoSomething; reintroduce; // The ancestor class also 
                                     // has a DoSomething method

Utilisez reintroduce quand vous voulez masquer une méthode virtuelle héritée par une nouvelle méthode.

Méthodes abstraites

Une méthode abstraite est une méthode virtuelle ou dynamique n'ayant pas d'implémentation dans la classe où elle est déclarée. Son implémentation est déléguée à une classe descendante. Les méthodes abstraites doivent être déclarées en spécifiant la directive abstract après virtual ou dynamic. Par exemple :

 procedure DoSomething; virtual; abstract;

Vous ne pouvez appeler une méthode abstraite que dans une classe ou une instance d'une classe dans laquelle la méthode a été redéfinie.

Aucun commentaire: