Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Wie Methode als Pointer übergeben? (https://www.delphipraxis.net/197210-wie-methode-als-pointer-uebergeben.html)

BlueStarHH 22. Jul 2018 11:07

Wie Methode als Pointer übergeben?
 
Wie kann ich eine Methode einer Klasse an eine Funktion, die einen Pointer erwartet, übergeben?

Delphi-Quellcode:
TScript = class(TObject)
public
  procedure AddFunc(Func: Pointer);
end;

TMyClass = class(TObject)
private
  Script: TScript;
public
  function MyFunc(const s: string): string;
  procedure MyProc;
end;

...

procedure TMyClass.MyProc;
begin
  Script.AddFunc(@MyFunc); //<-- FEHLER: E2036 Varaible erforderlich
end;

DieDolly 22. Jul 2018 12:08

AW: Wie Methode als Pointer übergeben?
 
Vielleicht hilft das

Delphi-Quellcode:
 type
   TFunctionParameter = function(const value : integer) : string;
...
function One(const value : integer) : string;
begin
   result := IntToStr(value) ;
end;
function Two(const value : integer) : string;
begin
   result := IntToStr(2 * value) ;
end;
function DynamicFunction(f : TFunctionParameter) : string;
begin
   result := f(2006) ;
end;
...
//Example usage:
var
   s : string;
begin
   s := DynamicFunction(One) ;
   ShowMessage(s) ; //will display "2006"
   s := DynamicFunction(Two) ;
   ShowMessage(s) ; // will display "4012"
end;
https://www.thoughtco.com/function-o...ameter-1057606

BlueStarHH 22. Jul 2018 12:24

AW: Wie Methode als Pointer übergeben?
 
Zitat:

Zitat von DieDolly (Beitrag 1408294)
Vielleicht hilft das

Delphi-Quellcode:
 type
   TFunctionParameter = function(const value : integer) : string;
...
function One(const value : integer) : string;
begin
   result := IntToStr(value) ;
end;
function Two(const value : integer) : string;
begin
   result := IntToStr(2 * value) ;
end;
function DynamicFunction(f : TFunctionParameter) : string;
begin
   result := f(2006) ;
end;
...
//Example usage:
var
   s : string;
begin
   s := DynamicFunction(One) ;
   ShowMessage(s) ; //will display "2006"
   s := DynamicFunction(Two) ;
   ShowMessage(s) ; // will display "4012"
end;
https://www.thoughtco.com/function-o...ameter-1057606

Danke für die Mühe, aber es hilft nicht. Denn ich muss die Funktion zwingend als Pointer übergeben. Denn AddFunc(Func: Pointer); ist aus einer Dritthersteller-Lib und kann nicht geändert werden.

himitsu 22. Jul 2018 13:00

AW: Wie Methode als Pointer übergeben?
 
Ein Methoden-Zeiger und auch die Class-Function bestehen aus zwei Pointern (Objekt-Instanz und Funktion-Zeiger)
und es ist unmöglich sie in nur einem Pointer zu speichern.

Static-Class-Funktions und reguläre Funktionen haben kein Self und bestehen nur aus einem Zeiger.



Einen Zeiger auf eine Variable mit dem Methodenzeiger.
* zeigt auf eine Variable irgendwo
* oder eine neue Variable mit New erstellt
* oder eine eben eine reguläre Funktion verlinken

dummzeuch 22. Jul 2018 14:36

AW: Wie Methode als Pointer übergeben?
 
Zitat:

Zitat von BlueStarHH (Beitrag 1408292)
Wie kann ich eine Methode einer Klasse an eine Funktion, die einen Pointer erwartet, übergeben?

Delphi-Quellcode:
TScript = class(TObject)
public
  procedure AddFunc(Func: Pointer);
end;

TMyClass = class(TObject)
private
  Script: TScript;
public
  function MyFunc(const s: string): string;
  procedure MyProc;
end;

...

procedure TMyClass.MyProc;
begin
  Script.AddFunc(@MyFunc); //<-- FEHLER: E2036 Varaible erforderlich
end;

Wie himitsu schon schreibt: Das geht nicht.

In der Regel behilft man sich damit, dass man eine function schreibt, die dann mittels einer globalen Referenz die Methode der Klasse aufruft.

Delphi-Quellcode:
var
  gblClass: TMyClass;

function Callback(const s: string): string;
begin
  Result := gblClass.MyFunc(s);
end;

procedure TMyClass.MyProc;
begin
  gblClass := Self;
  Script.AddFunc(@Callback);
end;
Häufig haben 3rd Party Bibliotheken (oder auch Windows APIs) zu diesem Zweck einen zusätzlichen Pointer-Parameter, der es einem erlaubt sowohl die function als auch die Objektreferenz zu übergeben. Dann geht es ohne die globale Referenz:

Delphi-Quellcode:
TScript = class(TObject)
public
  procedure AddFunc(Func: Pointer; data: pointer);
end;

function Callback(data: pointer; const s: string): string;
begin
  Result := TMyClass(data).MyFunc(s);
end;

procedure TMyClass.MyProc;
begin
  Script.AddFunc(@Callback, Self);
end;

BlueStarHH 22. Jul 2018 14:41

AW: Wie Methode als Pointer übergeben?
 
Zitat:

Zitat von dummzeuch (Beitrag 1408311)
In der Regel behilft man sich damit, dass man eine function schreibt, die dann mittels einer globalen Referenz die Methode der Klasse aufruft.

Delphi-Quellcode:
var
  gblClass: TMyClass;

function Callback(const s: string): string;
begin
  Result := gblClass.MyFunc(s);
end;

procedure TMyClass.MyProc;
begin
  gblClass := Self;
  Script.AddFunc(@Callback);
end;

Das sieht schonmal gut aus. Danke! Kann man das noch kürzer hinbekommen, da es sehr viele solcher Methoden gibt? Irgendwie eine anonyme Methode als Pointer übergeben und dort die eigentliche Methode der Klasse aufrufen? So in Pseudocode:

Delphi-Quellcode:
procedure TMyClass.MyProc;
begin
  gblClass := Self;
 
  Script.AddFunc(procedure Callback(const s: string)
    begin
      Result := gblClass.MyFunc(s);
    end
  );

end;

Blup 1. Aug 2018 11:55

AW: Wie Methode als Pointer übergeben?
 
Ich würde für jede Methode eine eigene Klasse erstellen.
Der Script-Liste dann jeweils Instanzen der Klassen hinzufügen.

Konzept:
Delphi-Quellcode:
TCustomDraw = class
public
  procedure Draw(ACanvas: TCanvas); virtual; abstract;
end;

TLine = class(TCustomDraw)
  constructor Create(x1, y1, x2, y2: Integer);
public
  procedure Draw(ACanvas: TCanvas); override;
end;

TCircle = class(TCustomDraw)
  constructor Create(x, y, r: Integer);
public
  procedure Draw(ACanvas: TCanvas); override;
end;

procedure BuildScript;
begin
  Script.Add(TLine.Create(5, 4, 8, 9));
  Script.Add(TCircle.Create(5, 4, 2));
  Script.Add(TCircle.Create(8, 9, 2));
end;

procedure ExecuteScript(ACanvas: TCanvas);
var
  cmd: TCustomDraw;
begin
  for cmd in Script do
    cmd.Draw(ACanvas);
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:25 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz