Méthodes (Object Pascal)

De Appmethod Topics
Aller à : navigation, rechercher

Remonter à Classes et objets - Index


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ù:

  • binding correspond à virtual, dynamic ou override ;
  • convention d'appel correspond à register, pascal, cdecl, stdcall ou safecall ;
  • avertissement correspond à platform, deprecated ou library.

Pour de plus amples informations à propos de ces directives de conseil, voir Déclarations et instructions#Directives de conseil. Toutes les directives sont listées dans Eléments syntaxiques fondamentaux#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 se réfère à la méthode héritée de même nom que la méthode englobante ou, si la méthode englobante est un gestionnaire de messages, au gestionnaire de messages 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 prend un seul paramètre de type TCollection. Ainsi, 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 de plus amples informations à propos de 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 de 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 ; voir Surcharge des méthodes.

Le compilateur Object Pascal supporte aussi le concept de méthode virtuelle final. Lorsque le mot-clé final est appliqué à une méthode virtuelle, aucune classe descendante ne peut redéfinir cette méthode. 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.

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

Dans Object Pascal 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 observable. Utilisez généralement les méthodes virtuelles.

Redéfinition ou masque

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 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 avec 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.

Méthodes de classe

La plupart des méthodes sont appelées méthodes d'instance, car elles opèrent sur une instance individuelle d'un objet. Une méthode de classe est une méthode (autre qu'un constructeur) qui agit sur des classes et pas sur des objets. Il existe deux types de méthodes de classe : les méthodes de classe ordinaires et les méthodes statiques de classe.

Méthodes de classe ordinaires

La définition d'une méthode de classe doit commencer par le mot réservé class. Par exemple :

type
  TFigure = class
  public
     class function Supports(Operation: string): Boolean; virtual;
     class procedure GetInfo(var Info: TFigureInfo); virtual;
     ...
  end;

La déclaration de définition d'une méthode de classe doit aussi commencer par class. Par exemple :

class procedure TFigure.GetInfo(var Info: TFigureInfo);
begin
    ...
end;

Dans la déclaration de définition d'une méthode de classe, l'identificateur Self représente la classe où la méthode est appelée (ce peut être un descendant de la classe dans laquelle elle est définie). Si la méthode est appelée dans la classe C, alors Self est de type class of C. Vous ne pouvez donc pas utiliser Self pour accéder à des champs d'instance, des propriétés d'instance et des méthodes normales (objet). Vous pouvez utiliser Self pour appeler les constructeurs ou d'autres méthodes de classe, ou pour accéder aux propriétés de classe et aux champs de classe.

Une méthode de classe peut être appelée via une référence de classe ou une référence d'objet. Quand elle est appelée via une référence d'objet, la classe de l'objet devient la valeur de Self.

Méthodes statiques de classe

Comme les méthodes de classe, les méthodes statiques de classe peuvent être accessibles sans une référence d'objet. A la différence des méthodes de classe ordinaires, les méthodes statiques de classe n'ont pas de paramètre Self. Elles ne peuvent pas accéder aux membres d'instance. Elles peuvent toujours accéder aux champs de classe, aux propriétés de classe et aux méthodes de classe. En outre, contrairement aux méthodes de classe, les méthodes statiques de classe ne peuvent pas être déclarées virtual.

Pour rendre une méthode de classe statique, ajoutez le mot static à leur déclaration, par exemple :

type
   TMyClass = class
     strict private
       class var
         FX: Integer;

     strict protected
       // Note: Accessors for class properties
       // must be declared class static.
       class function GetX: Integer; static;
       class procedure SetX(val: Integer); static;

     public
       class property X: Integer read GetX write SetX;
       class procedure StatProc(s: String); static;
   end;

Comme pour une méthode de classe, vous pouvez appeler une méthode statique de classe par l'intermédiaire du type de la classe (par exemple, sans référence d'objet), comme suit :

TMyClass.X := 17;
TMyClass.StatProc('Hello');

Surcharge des méthodes

Une méthode peut être redéclarée en utilisant la directive overload. Dans ce cas, si la méthode redéclarée a une signature de paramètre différente de celle de son ancêtre, elle surcharge la méthode héritée sans la cacher. L'appel de la méthode dans une classe descendante active l'implémentation qui correspond aux paramètres de l'appel.

Si vous surchargez une méthode virtuelle, utilisez la directive reintroduce quand vous la redéclarez dans les classes descendantes. Par exemple :

type
  T1 = class(TObject)
    procedure Test(I: Integer); overload; virtual;
  end;

  T2 = class(T1)
    procedure Test(S: string); reintroduce; overload;
  end;
  ...

SomeObject := T2.Create;
SomeObject.Test('Hello!');       // calls T2.Test
SomeObject.Test(7);              // calls T1.Test

A l'intérieur d'une classe, vous ne pouvez pas publier de multiples méthodes surchargées avec le même nom. La maintenance des informations de type à l'exécution requiert un nom unique pour chaque membre publié.

type
    TSomeClass = class
      published
        function Func(P: Integer): Integer;
        function Func(P: Boolean): Integer;   // error
          ...

Les méthodes qui servent de spécificateurs de lecture ou d'écriture de propriétés ne peuvent pas être surchargées.

L'implémentation d'une méthode surchargée doit répéter la liste de paramètres depuis la déclaration de classe. Pour de plus amples informations sur la surcharge, voir "Surcharge de procédures et de fonctions" dans Procédures et fonctions.

Constructeurs

Un constructeur est une méthode spéciale qui crée et initialise des instances d'objet. La déclaration d'un constructeur ressemble à celle d'une procédure, mais en commençant par le mot constructor. Exemples :

constructor Create;
constructor Create(AOwner: TComponent);

Les constructeurs doivent utiliser la convention d'appel register par défaut. Bien que la déclaration ne spécifie pas de valeur de retour, un constructeur renvoie une référence à l'objet qu'il a créé ou qui est appelé.

Une classe peut avoir plusieurs constructeurs mais doit en avoir au moins un. L'habitude veut qu'on appelle le constructeur Create.

Pour créer un objet, appelez la méthode constructeur sur un type classe. Par exemple :

MyObject := TMyClass.Create;

Cette instruction alloue le stockage pour le nouvel objet, définit la valeur de tous les champs ordinaux sur zéro, assigne nil à tous les champs de type pointeur ou de type classe, et une chaîne vide à tous les champs chaîne. Les autres actions spécifiées dans l'implémentation du constructeur sont effectuées ensuite. Généralement, les objets sont initialisés en fonction des valeurs transmises comme paramètres au constructeur. Enfin, le constructeur renvoie une référence à l'objet qui vient d'être créé et initialisé. Le type de la valeur de retour est le même que le type classe spécifié dans l'appel du constructeur.

Si une exception est déclenchée lors de l'exécution d'un constructeur invoqué sur une référence de classe, le destructeur Destroy est appelé automatiquement pour détruire l'objet inachevé.

Quand un constructeur est appelé en utilisant une référence d'objet (au lieu d'une référence de classe), il ne crée pas d'objet. Le constructeur agit à la place sur l'objet spécifié, en n'exécutant que les instructions de l'implémentation du constructeur et renvoie ensuite une référence à l'objet. Un constructeur est typiquement invoqué sur une référence d'objet en conjonction avec le mot réservé inherited afin d'exécuter un constructeur hérité.

Voici un exemple de type classe et de son constructeur :

 type
   TShape = class(TGraphicControl)
     private
       FPen: TPen;
       FBrush: TBrush;
       procedure PenChanged(Sender: TObject);
       procedure BrushChanged(Sender: TObject);
     public
       constructor Create(Owner: TComponent); override;
       destructor Destroy; override;
       ...
   end;

constructor TShape.Create(Owner: TComponent);
begin
    inherited Create(Owner);     // Initialize inherited parts
    Width := 65;          // Change inherited properties
    Height := 65;
    FPen := TPen.Create;  // Initialize new fields
    FPen.OnChange := PenChanged;
    FBrush := TBrush.Create;
    FBrush.OnChange := BrushChanged;
end;

Généralement, la première action d'un constructeur est d'appeler le constructeur hérité afin d'initialiser les champs hérités de l'objet. Le constructeur initialise ensuite les champs introduits dans la classe descendante. Comme un constructeur efface toujours le stockage alloué à un nouvel objet, tous les champs contiennent au départ zéro (pour les types ordinaux), nil (types pointeur et classe), chaîne vide (types chaîne) ou Unassigned (variants). Il n'est donc pas nécessaire que l'implémentation du constructeur initialise les champs sauf ceux devant contenir une valeur non nulle ou non vide.

Quand il est invoqué par le biais d'un identificateur de type classe, un constructeur déclaré comme virtual est équivalent à un constructeur statique. Quand ils sont combinés avec des types référence de classe, les constructeurs virtuels permettent une construction polymorphique des objets, c'est-à-dire la construction d'objets dont le type est inconnu à la compilation. Voir Références de classes.

Destructeurs

Un destructeur est une méthode spéciale qui détruit l'objet à l'endroit de son appel et libère sa mémoire. La déclaration d'un destructeur ressemble à celle d'une procédure, mais elle commence par le mot destructor. Exemple :

destructor SpecialDestructor(SaveData: Boolean);
destructor Destroy; override;

Les destructeurs sur Win32 doivent utiliser la convention d'appel register par défaut. Même si une classe peut avoir plusieurs destructeurs, il est conseillé que chaque classe redéfinisse la méthode Destroy héritée et ne déclare pas d'autres destructeurs.

Pour appeler un destructeur, vous devez référencer une instance d'objet. Par exemple :

MyObject.Destroy;

Lors de l'appel d'un destructeur, les actions spécifiées dans l'implémentation du destructeur sont d'abord exécutées. Typiquement, cela consiste à détruire les objets incorporés et à libérer les ressources allouées par l'objet. Ensuite, le stockage alloué à l'objet est libéré.

Voici un exemple d'implémentation d'un destructeur :

destructor TShape.Destroy;
begin
    FBrush.Free;
    FPen.Free;
    inherited Destroy;
end;

Typiquement, la dernière action de l'implémentation d'un destructeur est l'appel du destructeur hérité afin de détruire les champs hérités de l'objet.

Quand une exception est déclenchée lors de la création d'un objet, Destroy est appelée automatiquement afin de libérer l'objet inachevé. Cela signifie que Destroy doit être préparé à libérer des objets partiellement construits. Comme un constructeur définit les champs d'un nouvel objet sur zéro ou sur des valeurs vides avant d'effectuer d'autres actions, les champs de type classe ou pointeur d'un objet partiellement construit sont toujours définis sur nil. Un destructeur doit donc tester les valeurs nil avant d'agir sur des champs de type classe ou pointeur. L'appel de la méthode Free (définie dans TObject) au lieu de Destroy, permet de tester facilement les valeurs nil avant de détruire un objet.

Constructeurs de classes

Un constructeur de classe est une méthode de classe spéciale qui n'est pas accessible aux développeurs. Les appels des constructeurs de classes sont automatiquement insérés par le compilateur dans la section d'initialisation de l'unité où la classe est définie. Normalement, les constructeurs de classes sont utilisés pour initialiser les champs statiques de la classe ou effectuer un type d'initialisation, nécessaire avant que la classe ou toute instance de classe puisse fonctionner correctement. Même si le même résultat peut être obtenu en plaçant le code d'initialisation de la classe dans la section initialization, les constructeurs de classes ont l'avantage d'aider le compilateur à déterminer les classes qui doivent être incluses dans le fichier binaire final et celles qui doivent être retirées.

L'exemple suivant illustre la façon habituelle d'initialiser les champs de classes :

type
  TBox = class
  private
    class var FList: TList<Integer>;
  end;

implementation

initialization
  { Initialize the static FList member }
  TBox.FList := TList<Integer>.Create();

end.

Cette méthode a un gros désavantage : même si une application peut inclure l'unité dans laquelle TBox est déclaré, elle ne peut jamais réellement utiliser la classe TBox. Dans l'exemple en cours, la classe TBox est incluse dans le binaire résultant, car elle est référencée dans la section initialization. Pour alléger ce problème, considérons l'utilisation des constructeurs de classes :

type
  TBox = class
  private
    class var FList: TList<Integer>;
    class constructor Create;
  end;

implementation

class constructor TBox.Create;
begin
  { Initialize the static FList member }
  FList := TList<Integer>.Create();
end;

end.

Dans ce cas, le compilateur vérifie si TBox est réellement utilisé quelque part dans l'application, et en cas d'utilisation, un appel au constructeur de classe est ajouté automatiquement à la section initialization de l'unité.

Remarque : Même si le compilateur fait attention à l'ordre d'initialisation des classes, dans certains scénarios complexes, l'ordre peut devenir aléatoire. Cela se produit quand le constructeur d'une classe dépend de l'état d'une autre classe qui, à son tour, dépend de la première classe.

Remarque : Le constructeur de classe pour un enregistrement ou une classe générique peut s'exécuter plusieurs fois. Le nombre exact de fois que le constructeur de classe est exécuté dans ce cas dépend du nombre de versions spécialisées du type générique. Par exemple, le constructeur de classe pour une classe TList<String> spécialisée peut s'exécuter plusieurs fois dans la même application.

Destructeurs de classes

Les destructeurs de classes sont l'opposé des constructeurs de classes, dans le fait qu'ils réalisent la finalisation de la classe. Les destructeurs de classes viennent avec les mêmes avantages que les constructeurs de classes, à l'exception des fonctions de finalisation.

L'exemple suivant est construit sur l'exemple présenté dans les constructeurs de classes et il introduit la routine de finalisation :

type
  TBox = class
  private
    class var FList: TList<Integer>;
    class constructor Create;
    class destructor Destroy;
  end;

implementation

class constructor TBox.Create;
begin
  { Initialize the static FList member }
  FList := TList<Integer>.Create();
end;

class destructor TBox.Destroy;
begin
  { Finalize the static FList member }
  FList.Free;
end;

end.

Remarque : Le destructeur de classe pour un enregistrement ou une classe générique peut s'exécuter plusieurs fois. Le nombre exact de fois que le destructeur de classe est exécuté dans ce cas dépend du nombre de versions spécialisées du type générique. Par exemple, le destructeur de classe pour une classe TList<String> spécialisée peut s'exécuter plusieurs fois dans la même application.

Méthodes de messages

Les méthodes de messages implémentent des réponses à des messages répartis dynamiquement. La syntaxe des méthodes de messages est supportée sur toutes les plates-formes. VCL utilise des méthodes de messages pour répondre aux messages Windows.

Une méthode de message est créée en incluant la directive message dans une déclaration de méthode, suivie d'une constante entière comprise entre 1 et 49151 qui spécifie l'identificateur du message. Pour les méthodes de messages des contrôles VCL, la constante entière peut être un des identificateurs de messages Win32, avec les types d'enregistrements correspondants, dans l'unité Messages. Une méthode de message doit être une procédure qui n'attend qu'un seul paramètre var.

Par exemple :

type
    TTextBox = class(TCustomControl)
      private
       procedure WMChar(var Message: TWMChar); message WM_CHAR;
       ...
    end;

Une méthode de message n'a pas besoin d'inclure la directive override pour redéfinir une méthode de message héritée. En fait, il n'est pas nécessaire de spécifier le même nom de méthode ou type de paramètre que la méthode qu'elle redéfinit. L'identificateur du message détermine seul les messages auxquels la méthode répond et s'il s'agit d'une redéfinition.

Implémentation des méthodes de messages

L'implémentation d'une méthode de message peut appeler la méthode de message héritée, comme dans l'exemple suivant :

procedure TTextBox.WMChar(var Message: TWMChar);
begin
   if Message.CharCode = Ord(#13) then
      ProcessEnter
   else
      inherited;
end;

L'instruction inherited effectue une recherche arrière dans la hiérarchie des classes et invoque la première méthode de message ayant le même identificateur que la méthode en cours, et lui transmet automatiquement l'enregistrement message. Si aucune classe ancêtre n'implémente de méthode de message pour l'identificateur spécifié, inherited appelle la méthode DefaultHandler définie initialement dans TObject.

L'implémentation de DefaultHandler dans TObject rend simplement le contrôle sans rien faire. En redéfinissant DefaultHandler, une classe peut implémenter sa propre gestion par défaut des messages. Sur Win32, la méthode DefaultHandler pour les contrôles appelle DefWindowProc de l'API Win32.

Répartition des messages

Les gestionnaires de messages sont rarement appelés directement. A la place, les messages sont répartis sur un objet en utilisant la méthode Dispatch héritée de TObject :

procedure Dispatch(var Message);

Le paramètre Message transmis à Dispatch doit être un enregistrement dont la première entrée est un champ de type Word contenant un identificateur de message.

La méthode Dispatch effectue une recherche arrière dans la hiérarchie des classes, en commençant par la classe de l'objet où elle est appelée, et invoque la première méthode de message pour l'identificateur qui lui a été transmis. Si aucune méthode de message n'est trouvée pour l'identificateur donné, Dispatch appelle DefaultHandler.

Voir aussi