AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Methodpointer - wie funktioniert's?

Ein Thema von yankee · begonnen am 3. Feb 2007 · letzter Beitrag vom 4. Feb 2007
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#1

Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 15:00
Hi @ll,

folgender Code:
Delphi-Quellcode:
type
  test =class
    function tut(arg:string):Boolean;
  end;

implementation

function test.tut(arg:string):Boolean;
begin
  result :=true;
end;

function NichtMethode(arg:string):Boolean;
begin
  result :=true;
end;

function doStuff()
var p:pointer;
    t:test;
begin
  t :=test.Create;
  p :=@test.tut; //Compilerfehler: Variable required
  p :=@NichtMethode; //funktioniert.
end;
Wenn ich bei dieser Konstruktion doStuff aufrufe, klappt das nicht ganz so, wie ich mir das vorstelle...
Wieso? Wie macht man's richtig?

EDIT:
p :=test.tut (Also Zugriff als static) funktioniert...
Für meinen Fall reicht das sogar... Aber in anderen Fällen...? Wie macht man es, wenn man self haben will?

EDIT2:
Nein... funktioniert doch nicht...
Denn wenn ich den Pointer wieder zu meiner Funktion caste und dann verushc edie Funktion aufzurufen, bekomme ich einen Compilererror:
F2084 Internal Error: C4905
Das ist natürlich sehr informativ *stöhn*
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#2

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 16:30
Zitat von yankee:
folgender Code:
Delphi-Quellcode:
begin
  t :=test.Create;
  p :=@test.tut; //Compilerfehler: Variable required
  p :=@NichtMethode; //funktioniert.
end;
Wenn ich bei dieser Konstruktion doStuff aufrufe, klappt das nicht ganz so, wie ich mir das vorstelle...
Wieso? Wie macht man's richtig?
Hi,
was genau stellst Du Dir denn vor?
Ich meine klar, Du möchtest Die Adresse einer Methode, aber warum?
Erstmal vorweg, Methodenzeiger sind typisierte Zeiger, die auf eine Methode mit bestimmter Signatur zeigen. Du könntest z.B. mit
Delphi-Quellcode:
type
  methodpointer = function (arg: String): Boolean of Object;
einen Datentypen erzeugen, dem Du dann auch wirklich (und ohne Probleme) die Adresse der Funktion zuweisen kannst. Für deinen Fall klappt das einfach nicht, da Delphi hier nicht weiß, dass Du dich auf die Adresse der Funktion und nicht auf die Adresse des Funktionsergebnisses beziehst. Ein anderes Problem dass Du hier hättest liegt in der Überladung einer Methode. Was soll dein Code liefern, wenn ich deine Klasse um folgendes erweiter?:

Delphi-Quellcode:
function test.tut:Boolean;
begin
  result :=true;
end;
Wird jetzt die Adresse von Deiner oder meiner Funktion in p gespeichert? Bei dem Datentypen wird dies eindeutig Durch die Signatur festgelegt.
Wie gesagt, eigentlich ist hier wichtiger zu wissen warum Du überhaupt nach Methodenzeigern suchst (und hast Du die Forensuche mal benutzt? )

Gruß Der Unwissende
  Mit Zitat antworten Zitat
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#3

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 16:44
Zitat von Der_Unwissende:
Hi,
was genau stellst Du Dir denn vor?
Ich meine klar, Du möchtest Die Adresse einer Methode, aber warum?
Ich habe mir einen kleinen Matheparser gebastelt. Der soll natürlich auch Funktionen wie sinus usw. aufrufen können. Also muss ich einem String eine Funktion zuordnen.
Das mache ich mit dem Dictionary, welches ich unter dem Titel "Hash-tabellen" in der Code-lib gefunden habe . Dadrin speicher ich dann immer einen Pointer auf die zugehörige Funktion.
Zitat von Der_Unwissende:
Erstmal vorweg, Methodenzeiger sind typisierte Zeiger, die auf eine Methode mit bestimmter Signatur zeigen. Du könntest z.B. mit
Delphi-Quellcode:
type
  methodpointer = function (arg: String): Boolean of Object;
einen Datentypen erzeugen, dem Du dann auch wirklich (und ohne Probleme) die Adresse der Funktion zuweisen kannst.
Ich habe meine Funktion schon so im type-Bereich deklariert und wenn ich dann die Funktion wieder aufrufe, dann caste ich den Pointer auch zurück:
methodenpointer(p)(args);
Was auch astrein funktioniert, solange es sich um eine Funktion und nicht um eine Methode handelt.
Zitat von Der_Unwissende:
Für deinen Fall klappt das einfach nicht, da Delphi hier nicht weiß, dass Du dich auf die Adresse der Funktion und nicht auf die Adresse des Funktionsergebnisses beziehst.
Wenn delphi das mit Funktionen kann... Muss es doch auch irgendwie mit Methoden gehen, oder?[]
Zitat von Der_Unwissende:
Ein anderes Problem dass Du hier hättest liegt in der Überladung einer Methode. Was soll dein Code liefern, wenn ich deine Klasse um folgendes erweiter?:
Ja, dass macht natürlich Sinn...
Aber auch das muss man doch irgendwie lösen können... Wie gesagt: Mit einfachen Funktionen, die keine Methoden sind, klappt es ja auch...
Zitat von Der_Unwissende:
Wie gesagt, eigentlich ist hier wichtiger zu wissen warum Du überhaupt nach Methodenzeigern suchst (und hast Du die Forensuche mal benutzt? )
Ja... Hab gesucht . Aber nichts dazu gefunden (.
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#4

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 16:55
Du kannst Methodenzeiger und Funktionszeiger nicht mischen. Ein Funktionzeiger ist 4 Byte groß (SizeOf(Pointer)) und ein Methodenzeiger ist 8 Byte (SizeOf(TMethod)) groß. Bei deinem Typecast nach Pointer verlierst du also 4 Bytes, die aber notwendig sind.
  Mit Zitat antworten Zitat
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#5

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 16:58
Zitat von jbg:
Du kannst Methodenzeiger und Funktionszeiger nicht mischen. Ein Funktionzeiger ist 4 Byte groß (SizeOf(Pointer)) und ein Methodenzeiger ist 8 Byte (SizeOf(TMethod)) groß. Bei deinem Typecast nach Pointer verlierst du also 4 Bytes, die aber notwendig sind.
Mist .
Ich müsste also entweder einen Pointer auf den Pointer nehmen, oder das Dictionary von Pointer auf Methodenpointer umschreiben...?
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#6

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 17:04
Zitat von yankee:
das Dictionary von Pointer auf Methodenpointer umschreiben...?
Das dürfte der bessere von beiden Wegen sein. Du musst aber genau wissen welcher von beiden nun ein Funktionzeiger und welcher ein Methodenzeiger ist. (Wobei du dass über das TMethod.Data Feld ermitteln könntest))
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#7

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 17:07
Zitat von yankee:
Ich habe mir einen kleinen Matheparser gebastelt. Der soll natürlich auch Funktionen wie sinus usw. aufrufen können. Also muss ich einem String eine Funktion zuordnen.
Das mache ich mit dem Dictionary, welches ich unter dem Titel "Hash-tabellen" in der Code-lib gefunden habe . Dadrin speicher ich dann immer einen Pointer auf die zugehörige Funktion.
Da würde ich Dir dann auch gleich zu einem anderen Weg raten. Da Du eh Methoden verwendest, kannst Du gleich einen Ansatz wählen, der ein wenig mehr OOP ist. Die Umsetzung ist sehr elegant mit dem Command-Pattern (hoffe ich irre mich gerade nicht was den Namen angeht) möglich.
Die Idee ist einfach und häufig nötig, da viele moderne Sprachen auf explizite Zeiger (zum Glück) verzichten. Die einfache Idee besteht darin, dass Du statt einem Methodenzeiger einfach eine abstrakte Klasse oder ein Interface erstellst, dass die Methode die Du aufrufen möchtest enthält. Diese Methode ist dabei abstrakt (also noch nicht implementiert).
Für jede Methode die Du aufrufen möchtest erstellst Du dann einfach eine Klasse, die von der abstrakten Klasse erbt bzw. das entsprechende Interface implementiert.
Da wo die Methoden aufgerufen werden, brauchst Du nur noch eine Instanz der abstrakten Klasse oder des Interface. Was hier wirklich hinter steckt kann Dir egal sein, der Aufruf der Methode führt natürlich zum Aufruf der tatsächlichen Implementierung.

Delphi-Quellcode:
type
  IBase = interface
    procedure doFoo(const arg: String); // implizit abstract und public
  end;

  TFoo = class(TInterfacedObject, IBase)
    public
      procedure doFoo(const arg: String);
  end;

  TBar = class(TInterfaceObject, IBase)
    public
      procedure doFOo(const arg: String);
  end;

....
Hier hättest Du jetzt zwei verschidene Implementierungen des Interfaces. Nun kannst Du einfach für jede Klasse jeweils eine Instanz erzeugen und in deiner Map speichern. Für jeden String, den Du parst, holst Du dir dann aus der Map einfach ein Interface, von dem Du weißt das Du es in ein IBase-Interface casten und die Methode doFoo aufrufen kannst.
Ok, glaube die Maps arbeiten lieber mit Objekten zusammen, da würde sich eventuelle doch eine abstrakte Klasse besser machen.

Ich hoffe jedenfalls, dass die Idee grob klar ist. Entspricht einfach nur der OOP-Variante eines Methodenzeigers (die Idee ist natürlich komplett die gleiche)
  Mit Zitat antworten Zitat
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#8

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 17:43
Das Grundsätzliche Prinzip von Interfaces ist mir klar (bis jetzt habe ich aber Interfaces noch nie in Delphi verwendet. In Java aber schon).
Nur ist mir noch nicht ganz klar, wie mir das hilft... Bzw. wie du meinst, dass ich die Interfaces sinnvoll integrieren kann.
Delphi-Quellcode:
  Isin = interface
    procedure sin(const arg: extended);
  end;
  Icos = interface
    procedure cos(const arg: extended);
  end;
  ...
  TMyClass =class(Icos, Isin, ...)
    procedure cos(const arg: extended);
    procedure sin(const arg: extended);
    ...
  end;
  
function callMyFunc(name: string)
begin
  //und jetzt? Ich will die Funktion mit dem name den ich übergeben habe aufrufen...
  //aber wie helfen mir dabei die Interfaces?
end;
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#9

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 19:58
Zitat von yankee:
Delphi-Quellcode:
  Isin = interface
    procedure sin(const arg: extended);
  end;
  Icos = interface
    procedure cos(const arg: extended);
  end;
  ...
  TMyClass =class(Icos, Isin, ...)
    procedure cos(const arg: extended);
    procedure sin(const arg: extended);
    ...
  end;
  
function callMyFunc(name: string)
begin
  //und jetzt? Ich will die Funktion mit dem name den ich übergeben habe aufrufen...
  //aber wie helfen mir dabei die Interfaces?
end;
Ok, nimm einfach mal die Map, die Du schon hast. Hier kannst Du ja irgendwie ein Tupel aus String und Adresse speichern und zu einem String eine Adresse anfragen (lookup).
Du erzeugst jetzt also erstmal von jedem Interface (bzw. von der implementierenden Klasse) eine Instanz. Ah, seh gerade was Du falsch verstanden hast. Du hast das mit der Anzahl der Klasse und Interfaces etwas vertauscht.

Delphi-Quellcode:
type
  IFunction = interface
    function doWork(const argument: Extended): TResultType;
  end;

  // Gut, an der Benennung könnte man arbeiten, aber Du machst das schon!
  
  TCos = class(TInterfacedObject, IFunction)
    public
      function doWork(const argument: Extended): TResultType;
  end;

  TSin = class(TInterfacedObject, IFunction)
    public
      function doWork(const argument: Extended): TResultType;
  end;
Gut, wie die zu implementieren sind ist klar. Jetzt kommt die eigentliche Idee, statt Zeiger auf eine Funktion direkt im Dictionary zu speichern, legst Du nun die Interfaces ab. Da ich gerade nicht weiß wie dein Dictionary aufgebaut ist (dass, das Du verwendest) gehe ich der Einfachheit halber einfach von einer Klasse TDictionary aus, der ich mittels add(String, Interface) ein Element hinzufügen kann und die per Lookup(String): Interface mir ein Interface zurück gibt (musst Du dann nur entsprechend anpassen).

Delphi-Quellcode:
// füllen des Dictionary
var buffer: IFunction;
begin
  GlobalDict := TDictionary.Create(...);
  
  buffer := TSin.Create;
  GlobalDict.Add('sin', buffer);

  buffer := TCos.Create;
  GlobalDict.Add('cos', buffer);
  
  // ....
end;

// und jetzt das eigentliche Aufrufen:
function callMyFunc(name: string): FunctionResult;
var funcWrapper: IFunction;
begin
  funcWrapper := IFunction(GlobalDict.Lookup(name));
  result := funcWrapper.doWork(ExtendedArgument);
end;
Hier hast Du also den Vorteil, dass Du ganz unterschiedliche Klassen im Dictionary abspeicherst, die alle das Interface IFunction implentieren. D.h. hier also, dass Du weißt, dass alles was aus dem Dictionary kommt eine Funktion doWork hat (Ergebnis und Funktionsparameter stehen auch fest). So realisiert man z.B. auch Callbacks in Java (da es ja keine andere Möglichkeit gibt). Ich weiß nicht ob Du in Java mal mit Swing gearbeitet hast? Könnte Dich dann an die Ereignis-Benachrichtigung (einen Listener) erinnern.

Hoffe ist etwas klarer wie ich das meinte (und das nicht wieder ein roter Kasten fehlt).
  Mit Zitat antworten Zitat
Hawkeye219

Registriert seit: 18. Feb 2006
Ort: Stolberg
2.227 Beiträge
 
Delphi 2010 Professional
 
#10

Re: Methodpointer - wie funktioniert's?

  Alt 3. Feb 2007, 20:17
Hi,

der harte TypeCast dürfte aber zu einer Exception führen. Besser wäre es so:

Delphi-Quellcode:
function callMyFunc(name: string): TResultType;
var funcWrapper: IFunction;
begin
  if Supports(GlobalDict.Lookup(name), IFunction, funcWrapper) then
    result := funcWrapper.doWork(ExtendedArgument)
  else
    result := ...
end;
Voraussetzung für den Einsatz der Funktion Supports ist aber, daß die Interfaces eine eindeutige GUID besitzen:

Delphi-Quellcode:
type
  IFunction = interface
    ['{4C30EFEE-10A6-4B88-919E-9CD12673572F}']
    function doWork(const argument: Extended): TResultType;
  end;
Diese kann man im Editor über die Tastenkombination [Umsch][Strg][G] leicht erzeugen lassen.

Gruß Hawkeye
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:33 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