[gelöst] Constructor in Variable Speichern

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

[gelöst] Constructor in Variable Speichern

Beitrag von MAC »

Hallo,

für mein aktuelles Problem in http://www.lazarusforum.de/viewtopic.php?f=10&t=8161
wäre es hilfreich zu wissen wie ein Constructor intern aufgebaut ist.
Um genauer zu sein möchte ich einen Constructor, genau wie eine Funktion in einer Variable (z.B: pointer) abspeichern und aufrufen.

Von Delphi hab ich diesen Hinweis bekommen (der in Lazarus aber nur manchmal funktioniert)

Code: Alles auswählen

type
  TaConstructor = function(Self: TClass; DoAlloc: Boolean): TObject;
var
  p:pointer;
  aClass:TClass;
  aObj:TObject;
begin
aClass := TObject;
p := @TObject.Create;
// now create TObject like this
aObj := TaConstructor(p)(aClass,false);
end;
Kann man irgendwo nachschauen, welche Parameter bei Lazarus übergeben werden muss und was diese genau ändern, um das Object richtig zu erstellen.
Was passiert wenn der User einen Constructor mit weiteren Parametern erstellt hat? Was macht Lazarus / fpc dann?

Danke
Zuletzt geändert von MAC am Fr 24. Okt 2014, 21:15, insgesamt 1-mal geändert.

Code: Alles auswählen

Signatur := nil;

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Constructor in Variable Speichern

Beitrag von mschnell »

MAC hat geschrieben:Was passiert wenn der User einen Constructor mit weiteren Parametern erstellt hat? Was macht Lazarus / fpc dann?
Nichts besonderes.

Der Benutzer muss in seinem Constructor mit "inherited" den Constructor der Vorgänger-Klasse aufrufen. Das passiert dann über beliebig viele Ebenen und jede Nachfolger-Klasse fügt dann auf dem "Rückweg" ihre spezifischen Instanz-Variablen etc hinzu.

Später beim instanziieren wird immer eine Instanz der Hierarchie-Stufe erstellt, deren Klassen-Name bei Instanz := Klassenname.Create(...), angegeben ist.

-Michael

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: Constructor in Variable Speichern

Beitrag von MAC »

mschnell hat geschrieben:
MAC hat geschrieben:Was passiert wenn der User einen Constructor mit weiteren Parametern erstellt hat? Was macht Lazarus / fpc dann?
Nichts besonderes.

Der Benutzer muss in seinem Constructor mit "inherited" den Constructor der Vorgänger-Klasse aufrufen. Das passiert dann über beliebig viele Ebenen und jede Nachfolger-Klasse fügt dann auf dem "Rückweg" ihre spezifischen Instanz-Variablen etc hinzu.

Später beim instanziieren wird immer eine Instanz der Hierarchie-Stufe erstellt, deren Klassen-Name bei Instanz := Klassenname.Create(...), angegeben ist.

-Michael
Dann hab ich meine Frage wohl etwas falsch formuliert.
Angenommen dieser Code passt zum Konstruktor und damit kann der Konstruktor als "function" in einer Variable abgespeichert werden.

Code: Alles auswählen

 
type
  TaConstructor = function(Self: TClass; DoAlloc: Boolean): TObject;
 
constructor TMyObject.Create;
begin
end;
 
var
 p:TaConstructor;
begin
p := @TMyObject.Create;
end. 
 
Wie sähe dann der Konstruktor Intern aus, wenn TmyObject weitere Parameter benötigt

Code: Alles auswählen

 
type
  TMoeglichkeit1 = function(Self: TClass; DoAlloc: Boolean; WeitererParameter:integer): TObject;
  TMoeglichkeit2 = function(Self: TClass; WeitererParameter:integer; DoAlloc: Boolean): TObject;
  TMoeglichkeit3 = function(WeitererParameter:integer; Self: TClass; DoAlloc: Boolean): TObject;
  TMoeglichkeit4 = ?;
 
constructor TMyObject.Create(WeitererParameter:integer);
begin
end;
 
 
var
 p:TMoeglichkeit1;
begin
p := @TMoeglichkeit1.Create;
end. 
 

Code: Alles auswählen

Signatur := nil;

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: Constructor in Variable Speichern

Beitrag von Socke »

Die zusätzlichen Parameter werden am Ende an die Parameterliste angehangen; siehe http://www.freepascal.org/docs-html/pro ... 810006.5.2

Auf der anderen Seite stellt sich die Frage, was du damit bezwecken möchtest. Parameter im Konstruktor zu fordern hat gerade den Zweck, sie verpflichtend zu machen; wenn du die nicht weißt, welche Parameter übergeben werden müssen, kannst du sie auch nicht angeben und das erstellte Objekt ist unvollständig.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: Constructor in Variable Speichern

Beitrag von MAC »

Danke, genau so eine Seite hab ich gesucht.
Wie bereits gesagt: Ich möchte im anderen Thread den richtigen Constructor dynamisch aufrufen.
Ich schätze nicht das das anhand des Klassennamens alleine geht (ohne einen virtuellen Constructor). Und verlange jetzt sowohl die Classe als auch einen Pointer auf den Constructor um das ganze dynamisch zu machen.
Um die Parameter später nutzen zu können werd ich wohl noch ein Workaround brauchen. Das sollte aber kein so großes Problem werden ...

Ich schau mir das heute Abend mal an, und makiere dann das Thema als beantworted sobald alles klappt :)

Code: Alles auswählen

Signatur := nil;

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: Constructor in Variable Speichern

Beitrag von Socke »

MAC hat geschrieben:Ich schätze nicht das das anhand des Klassennamens alleine geht (ohne einen virtuellen Constructor). Und verlange jetzt sowohl die Classe als auch einen Pointer auf den Constructor um das ganze dynamisch zu machen.
Um die Parameter später nutzen zu können werd ich wohl noch ein Workaround brauchen. Das sollte aber kein so großes Problem werden ...

Ich schau mir das heute Abend mal an, und makiere dann das Thema als beantworted sobald alles klappt :)
Mit der aktuellen FPC-Entwicklerversion kannst du die Parameter des Konstruktors über RTTI auslesen: http://wiki.freepascal.org/User_Changes ... _Variables Dann brauchst du eigentlich nur noch einen Zeiger auf die Klasse, einen Zeiger auf die Funktion (ohne einen konreten Funktions-Typen zu benennen) und einen Zeiger auf die Typinformationen.

Die Konstruktoren mit konkreten Werten zu versogen dürfte jedoch recht aufwändig werden. Zum einen können die Parameter unterschiedlich groß werden. Alles was zwischen 1 und 4 bzw. 8 Byte (32 vs. 64 Bit) liegt oder eine Referenz/Pointer ist, dürfte recht einfach zu machen sein; wenn du aber einen const Record hast, kannst du nicht voraussagen, ob der Record als Referenz oder als Kopie übergeben wird (der Compiler entscheidet im Einzelfall). Dazu kommen die verschiedenen Aufrufkonventionen. Ich denke aber, diese Arbeit wäre einen Feature-Request im Bug-Tracker wert ;-)
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Constructor in Variable Speichern

Beitrag von mschnell »

In vielen Fällen kannst Du - wenn Du die zu instanziierende Klasse selber schreibst - vermutlich mit gleichartigen Konstruktoren auskommen und nachträglich die zusätzlichen Werte mittels Properties setzen.

-Michael

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: Constructor in Variable Speichern

Beitrag von MAC »

So, ich habe ein Workaround gefunden, was zu gehen scheint.
Ich nenne es deshalb Workaround, weil es nicht ganz Sockes definition entspricht, aber Never change a Running system...

Um den Constructor in einer Variable zu speichern und dann später aufzurufen muss man folgendes machen:

Code: Alles auswählen

 
var
  aClass:TClass = TMyObject;
  apointer:pointer;
  bObject:TObject;
  aObject:TObject;
// 1. Den Constructor als Pointer irgendwo Abspeichern
apointer := @TMyObject.Create // TMyObject muss explizit angegeben werden. Es kann nicht einfach eine Variable vom Typ TClass verwendet werden!
//2. Den Constructor wie folgt interpretieren
TObjectCreate = function(Self: TObject; DoAlloc: Boolean): TObject;
//3. Es muss für den nächsten Punkt schon eine Instanz existieren, also erstellen wir eine mehr schlecht als recht
bObject := aClass.Create;
//4. Beim aufruf als Self, eine Instanz der Klasse mitgeben und bei DoAlloc true setzten. Ich wiederhole, ich weiß nicht warum das klappt, aber es scheint fehlerfrei zu funktionieren ;)
aObject := TObjectCreate (apointer)(bObject,true) 
Und voila, man hat ein Object mehr oder weniger dynamisch erstellt...

Code: Alles auswählen

Signatur := nil;

Antworten