2010-09-24 14 views
3

Voici mon exemple de code:Comment faire pour obtenir un pointeur vers une méthode dans une classe de base à partir d'une classe enfant dans Delphi?

type 
    TMyBaseClass = class 
    public 
    procedure SomeProc; virtual; 
    end; 

    TMyChildClass = class(TMyBaseClass) 
    public 
    procedure SomeProc; override; 
    end; 

var 
    SomeDelegate: procedure of object; 

procedure TMyBaseClass.SomeProc; 
begin 
    ShowMessage('Base proc'); 
end; 

procedure TMyChildClass.SomeProc; 
begin 
    ShowMessage('Child proc'); 
    // here i want to get a pointer to TMyBaseClass.SomeProc (NOT IN THIS CLASS!): 
    SomeDelegate := SomeProc; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    with TMyChildClass.Create do 
    try 
    // there will be "Child proc" message: 
    SomeProc; 
    finally 
    Free; 
    end; 
    // there i want to get "Base proc" message, but i get "Child proc" again 
    // (but it is destroyed anyway, how coud it be?): 
    SomeDelegate; 
end; 

Répondre

8

La seule façon que je connaisse est:

procedure TMyChildClass.BaseSomeProc; 
begin 
    inherited SomeProc; 
end; 


procedure TMyChildClass.SomeProc; 
begin 
    ShowMessage('Child proc'); 
    SomeDelegate := BaseSomeProc; 
end; 

Le 2ème est de changer SomeProc déclaration override-reintroduce:

TMyChildClass = class(TMyBaseClass) 
public 
    procedure SomeProc; reintroduce; 
end; 

puis cast self comme TMyBaseClass (ne pas utiliser as cast):Notez également que votre code donnera accès Violation parce que vous appelez SomeDelegate sur l'objet déjà libéré.

+0

Merci! La vôtre 1ère méthode est exacte ce que je veux =) – SomeOne

+1

S'il vous plaît faites attention à ce que Michal Niklas a dit à propos de la violation d'accès. Vous en aurez toujours un, même avec "hérité". C'est parce que vous ne pouvez pas avoir un pointeur vers une méthode d'une classe (à moins qu'il ne soit déclaré comme "procédure de classe"), seulement à une méthode d'un objet. Votre objet est détruit lorsque vous appelez Free(), et toutes les références, y compris SomeDelegate qui contient une référence à sa fonction, ne sont plus valides. – himself

+0

Lorsque j'ai essayé le code avec mon Turbo Delphi, j'ai eu une exception de violation d'accès. –

4

Ajout d'une déclaration de type et de certains travaux de typage, mais avec quelques notes d'avertissement.

Comme vous l'avez mentionné vous-même, l'appel à somedelegate après que l'instance a été libérée ne fait pas d'AV. C'est parce que votre méthode SomeProc n'utilise aucune variable d'instance, tout ce qu'elle appelle est ShowMessage.

Si vous ajoutez des variables d'instance à l'appel, vous pourriez même vous en sortir si la mémoire n'a pas été réaffectée. Ce serait un AV qui attend de se produire.

Bottom line:

  • ne pas appeler des méthodes sur les objets détruits.
  • La définition d'une variable globale à partir d'une instance d'une classe qui survit à la durée de vie de la classe n'est pas considérée comme une bonne conception.
  • Dans un design idéal, il ne devrait pas être nécessaire pour une classe enfant de rétablir un appel de toute façon à la méthode de l'ancêtre, autrement qu'en appelant inherited.

code change

... 
type 
    TSomeDelegate = procedure of object; 

var 
    SomeDelegate: TSomeDelegate; 

... 

procedure TMyChildClass.SomeProc; 
var 
    method: TMethod; 
begin 
    ShowMessage('Child proc'); 
    // here i want to get a pointer to TMyBaseClass.SomeProc (NOT IN THIS CLASS!): 
    method.Code := @TMyBaseClass.SomeProc; 
    method.Data := Self; 
    SomeDelegate := TSomeDelegate(method); 
end;