Problem rund um Funktionspointer

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
henlambert
Beiträge: 12
Registriert: Di 7. Mai 2013, 18:32

Problem rund um Funktionspointer

Beitrag von henlambert »

Hi,
zuerst mal guten Tag hier im Forum. Ich bin Neuling in Sachen Pascal und komme aus dem C/C++ Lager. Im Grunde ist der Umstieg kein Problem, doch an einer für mich sehr wichtigen Sache hänge ich fest. Es ist nicht ganz einfach, das Problem so zu schildern, dass ich richtig verstanden werde, aber ich versuch's mal, wobei ich einiges stark vereinfache.

Also, ich habe eine Unit "Winsys", in der u.a. die Eventschleife von SDL untergebracht ist. Tritt ein Ereignis ein, z.B. ein Tastendruck, wird aus dieser Schleife heraus der Event-Handler "Keyhandler" aufgerufen. So weit - so gut - so einfach. Aber es gibt zwei Besonderheiten:

1. Das Programm arbeitet mit verschiedenen Programmmodi, die jeweils eine eigene Implementation des Key-Handlers enthalten.
2. Jeder Programmmodus ist in einer eigenen Unit untergebracht; damit sind auch die Key-Handler nicht in der Unit Winsys enthalten, sondern in anderen Programmeinheiten.

Im Grunde "weiß" die Loopfunktion nicht mal, welcher Key-Handler gerade aktiv sein soll, und dennoch muss das Ereignis an die richtige Adresse weitergeleitet werden. Es gibt vielleicht die Möglichkeit, mit abstrakten Klassen zu arbeiten, aber das Verfahren ist ziemlich unübersichtlich. Wesentlich eleganter ist der Weg über Funktionspointer. Dazu wird in Winsys ein Array mit Funktionspointern angelegt, und jeder Modus trägt dort nach dem Programmstart den Zeiger auf seinen Keyhandler ein. Über eine einfache Enum-Variable kann von der Loop je nach Modus die passende Funktion selektiert und aufgerufen werden. Ebenso könnte man natürlich auch eine einzige Funkionsvariable nehmen und dort bei einem Moduswechsel in der Init-Phase den aktuellen Keyhandler eintragen. Beides funktioniert unter C++ hervorragend und ist einfach zu implementieren, doch ob das auch in Pascal geht (und wie!) weiß ich nicht. Ich rede gewohnheitsmäßig von Funktionen, meine damit natürlich auch Prozeduren, das sollte egal sein.

- Wie könnte die Typdeklaration der Funktion aussehen? Als Parameter wird ein Record (sagen wir mal TKeyParams) übergeben.
- Wie sieht die Variable aus, die die wechselnden Funktionszeiger aufnimmt?
- Wie wird die Funktion in dieser Variablen von der Winsys-Loop aufgerufen?
- Wie lautet der Term, mit dem ein Funktionszeiger aus der Modus-Unit übermittelt wird?


Nun verderbt mir bitte nicht den Spaß an Pascal, indem ihr mir mitteilt, dass das so nicht geht.
Gruß
Henlambert

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Problem rund um Funktionspointer

Beitrag von Socke »

henlambert hat geschrieben:- Wie könnte die Typdeklaration der Funktion aussehen? Als Parameter wird ein Record (sagen wir mal TKeyParams) übergeben.
- Wie sieht die Variable aus, die die wechselnden Funktionszeiger aufnimmt?
- Wie wird die Funktion in dieser Variablen von der Winsys-Loop aufgerufen?
- Wie lautet der Term, mit dem ein Funktionszeiger aus der Modus-Unit übermittelt wird?

Code: Alles auswählen

type
  // Parameter-Typen müssen natürlich vorab bekannt sein
  TKeyParams = record
    myvar1: Integer; // dein Inhalt
  end;
Die Typdeklaration für Funktionstypen folgt dem Schema:
Name = procedure/function (Parameter)[: Ergebnistyp] [of object]; [modifier]

Code: Alles auswählen

// Funktions-Typ für eine normale Prozedur
  TKeyCallback = procedure (const mypar: TKeyParams);
// Funktionstyp für eine normale Funktion
  TKeyCallbackFunc = function (const mypar: TKeyParams): Integer;
// Funktionstyp für eine Prozedur-Methode eines Objektes
  TKeyCallbackObj = procedure (const mypar: TKeyParams) of object;
Aufruf der Funktionen und Zuweisung der Funktionszeiger funktioniert dann so:

Code: Alles auswählen

// Variable für den Prozedurzeiger deklarieren
var
  pproc: TKeyCallback;
// natürlich geht das auch mit einem Array:
  pprocArray: array[0..2] of TKeyCallback;
 
// Der Key-Handler
procedure MyKeyHandler(const mypar: TKeyParams);
begin
  writeln('Hallo Welt!');
end;
 
// dann geht die Zuweisung so (Der Operator @ liefert in Pascal die Adresse des folgenden Ausdrucks)
pproc := @MyKeyHandler;
pprocArray[0] := @MyKeyHandler;
 
// Der Aufruf erfolgt ganz normal:
pproc(myvar);
// bzw.
pprocArray[0](myvar);
 
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

henlambert
Beiträge: 12
Registriert: Di 7. Mai 2013, 18:32

Re: Problem rund um Funktionspointer

Beitrag von henlambert »

Danke, das war eine präzise und erschöpfende Antwort. :D
Es funktioniert hervorragend. Ich kann übrigens allen, die nicht mit der LCL, sondern mit einer eigenen Eventschleife und z.B. SDL und OpenGL arbeiten, das Verfahren empfehlen. Es kommt mit minimalem Code aus, ist schnell und vor allem beliebig erweiterbar.

Antworten