![]() |
Delphi-Version: XE3
[XE3] Operator Overloading, Verhalten?
Moin,
Vorhin zum ersten mal mit Delphi und Operator Overloading beschäftigt. Von C++ kenn ich es schon. Das Delphi das seit Delphi2006 schon kann war mir neu. Bin vorhin erstmal auf die Nase gefallen. Ich dachte mir schön, dann leg ich jetzt mal nen eigenen Typ an und hinterlege da einen Wert + Verknüpfung auf ein Objekt. Hab dann die Variable lokal angelegt, und einfach mit v.object := irgendwas; und v:=100; initialisiert. Das klappt auch. ABER! wenn v ein feld einer klasse ist oder im globalen Teil steht, wird bei v:=100 das record neu initialisiert. Also der Pointer auf das Objekt ist dann nil. Interessanter weise bei lokalen variablen nicht. Auch nicht bei Release... Gut man kann das verhalten schnell korrigieren indem man alle Felder vom Record im class operator implict initialisiert... Aber ich hätte das Verhalten gerne. Also ich möchte am liebsten dem Record beim Anfang ein Objekt oder zweiten wert mitgeben, den es bei einer Operator Zuweisung behält (v:=100) Ist denke ich aber nicht möglich oder? Hier das Beispiel:
Delphi-Quellcode:
unit Unit2;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TVarX = record Value: integer; FormMaster: TForm; Name: string; class operator implicit(const z: integer): TVarX; // bei TvarX:=int end; TForm2 = class(TForm) Memo1: TMemo; procedure FormCreate(Sender: TObject); private FormVar1: TVarX; { Private-Deklarationen } procedure TestX; public { Public-Deklarationen } end; var Form2: TForm2; globalVar1: TVarX; implementation {$R *.dfm} { TVarX } class operator TVarX.implicit(const z: integer): TVarX; begin result.Value := z; end; { TForm2 } procedure TForm2.TestX; var localVar1: TVarX; begin localVar1 := 100; localVar1.Name := 'blubblub'; localVar1.FormMaster := self; localVar1 := 200; { value = 200, name = 'blubblub', formMaster=form2 } FormVar1 := 100; FormVar1.Name := 'blubblub'; FormVar1.FormMaster := self; FormVar1 := 200; { value = 200, name = '', formMaster=nil } globalVar1 := 100; globalVar1.Name := 'blubblub'; globalVar1.FormMaster := self; globalVar1 := 200; { value = 200, name = '', formMaster=nil } //zum testn bei build release... Memo1.Lines.Add('localVar1.Name' + ' : ' + localVar1.Name); //out blubblub Memo1.Lines.Add('FormVar1.Name' + ' : ' + FormVar1.Name); //out = '' Memo1.Lines.Add('globalVar1.Name' + ' : ' + globalVar1.Name); //out = '' end; procedure TForm2.FormCreate(Sender: TObject); begin TestX; end; end. |
AW: [XE3] Operator Overloading, Verhalten?
Ich denke eher das Verhalten bei localVar1 ist der Fehler. Der Implicit-Operator gibt immer einen kompletten Record zurück. Man hat eigentlich keinen Zugriff auf das Ziel der Zuweisung. Das wird auch deutlich, wenn du mal den Add-Operator implementierst und dann einfach mehrere Additionen in eine Zuweisung schreibst. Die daraus resultierenden Zwischenergebnisse müssen ja irgendwo liegen.
|
AW: [XE3] Operator Overloading, Verhalten?
Habs direkt mal getestet:
Delphi-Quellcode:
Also wird im lokalen Teil, nur der veränderte Wert übernommen.class operator TVarX.add(const a, b: TVarX): TVarX; begin result.Value:= a.Value+b.Value; end; ..... localVar1,l2,l3,lg: TVarX; ...... localVar1:=100; lg.Name:='asdfg'; l2:=localVar1; l3:=400; lg:=l2+l3; { value = 500, name = 'asdfg' } "lg" hat ja immer noch den zugewiesenen Wert vor der Addition. |
AW: [XE3] Operator Overloading, Verhalten?
Zitat:
Bei den beiden anderen Varianten wird der Record nach dem Operator jeweils überschrieben. Ich glaube auch nicht, dass das Absicht ist. |
AW: [XE3] Operator Overloading, Verhalten?
Delphi-Quellcode:
Ohne FormMaster:=nil kann es sein, daß FormMaster einen undefinierten Zufallswert enthält. (nicht NIL)
class operator TVarX.implicit(const z: integer): TVarX;
begin Result.FormMaster := nil; Result.Value := z; end; Und nun fällt es auch auf, warum dein .object zwangsweise verschwinden muß. Zitat:
Im Prinzip entspricht dein Code ja Folgendem, egal ob es jetzt ein Objekt oder Record ist. (wobei eher Interface, statt Objekt, wegen der automatischen Speicherverwaltung)
Delphi-Quellcode:
v.FormMaster := irgendwas;
v := TVarX.Create(100); // Parameter für "Value" // bzw. v.FormMaster := irgendwas; v := TVarX.Create; v.Value := 100; |
AW: [XE3] Operator Overloading, Verhalten?
Zitat:
Delphi-Quellcode:
Denn bei Records (über 8 bytes oder mit gemanageten Typen) und gemanageten Typen (Strings, Interfaces usw.) baut der Compiler das intern so um.
function GetStr(Value: integer): string;
begin Result := Result + IntToStr(i); end; var i: Integer; S: string; begin S := ''; for i := 0 to 100 do S := S + GetStr(i); ShowMessage(S); end;
Delphi-Quellcode:
procedure GetStr(Value: integer; var Result: string);
begin Result := Result + IntToStr(i); end; var i: Integer; S, AutoTempVar: string; begin S := ''; for i := 0 to 100 do begin GetStr(i, AutoTempVar); S := S + AutoTempVar; end; ShowMessage(S); end; |
AW: [XE3] Operator Overloading, Verhalten?
Zitat:
Zitat:
Delphi-Quellcode:
und du kannst damit auch nicht davon ausgehen, dass Felder irgendwie übernommen werden. Hier schlägt dann nämlich die Freiheit des Compilers zu, wie er das Result bzw. die Variable, auf die das Result von Implicit() zugewiesen wird, an die Implicit-Funktion übergeben wird (entweder ein Pointer auf eine bisherige Variable, Pointer auf eine temporäre Variable, die dann zu der anderen zugewiesen wird, etc.). Wie himitsu also bereits gesagt hat, musst du Result immer vollends initialisieren.
Self
Ich hab deinen Code auch mal unter FPC ausprobiert (wo das selbe Ergebnis rauskommt) und wenn man sich den generierten Assemblercode anschaut, so sieht man, dass im Fall von localVar1 die Adresse dieser Variablen selbst an Implicit() übergeben wird, während in den beiden anderen Fällen eine lokale temporäre Variable verwendet und diese anschließend an globalVar1 und FormVar1 kopiert wird. Gruß, Sven |
AW: [XE3] Operator Overloading, Verhalten?
OK, also ich denke wir können das damit abschließen,
ABER seht ihr da irgendeine alternative Möglichkeit mit, (nennen wir es mal Objekte) mit Objekten rechnen Operationen durchzuführen, und im Hintergrund jedem Objekt eine Referenzen auf andere Objekte zu halten? Ohne z.b. variable.wert! Bisher hab ich das so ähnlich gemacht:
Delphi-Quellcode:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Generics.Collections; type TVarIntX = record ValuePtr: PInteger; Objekt: TObject; end; TVarInt_List = TList<TVarIntX>; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private TestInt: integer; ListTest: TVarInt_List; procedure Test; function FindObjekt(varptr: PInteger): TObject; { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} function TForm1.FindObjekt(varptr: PInteger): TObject; var i:integer; v:TVarIntX; begin result:=nil; for I := 0 to ListTest.Count-1 do begin v:=ListTest[i]; if v.ValuePtr=varptr then begin result:=v.Objekt; break; end; end; end; procedure TForm1.Test; var v: TVarIntX; o:Tobject; begin // initialisieren.. v.ValuePtr := addr(TestInt); v.Objekt := self; ListTest.Add(v); // ------------------ TestInt := 100; TestInt := TestInt*2; TestInt := TestInt+200; //jetzt zugeordnetes objekt holen für irgendwas... o:=FindObjekt(addr(TestInt)); if Assigned(o) and (o is TForm) then (o as TForm).Caption:='test'; end; procedure TForm1.FormCreate(Sender: TObject); begin ListTest := TList<TVarIntX>.create(); Test(); end; procedure TForm1.FormDestroy(Sender: TObject); begin ListTest.Free; end; end. |
AW: [XE3] Operator Overloading, Verhalten?
Entweder ist dein Beispiel schlecht konstruiert oder du siehst den Wald vor lauter Bäumen nicht.
Warum der Umweg über den ValuePtr? Sag doch einfach
Delphi-Quellcode:
und in den Berechnungen nimmst du gleich
type
TVarIntX = record Value: Integer; Objekt: TObject; end;
Delphi-Quellcode:
anstatt
v.Value
Delphi-Quellcode:
.
TestInt
|
AW: [XE3] Operator Overloading, Verhalten?
Zitat:
Zitat:
In meinem Fall geht es um Mathematische Berechnungen mit Hunderten von diversen Variablen, die unterschiedlichen Objekten zugeordnet sind (teilweise auch Datenbanken). bei allen Variablen ein .value anzuhängen macht da keinen Sinn. Bisher gibt es vorm berechnen ein Load() und nach dem berechnen ein Save(), die jeweils ein paar seiten umfassen. Ich dachte mir, dass man das Load und Save evtl. vereinfachen könnte. Klar einmal Initialisieren bleibt, aber Load und Save könnten dann zwei schleifen sein.
Delphi-Quellcode:
for i := 0 to ListX.count-1 do
ListX[i].Save() //Load() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz