AGB  ·  Datenschutz  ·  Impressum  







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

[XE3] Operator Overloading, Verhalten?

Ein Thema von 4dk2 · begonnen am 20. Mär 2014 · letzter Beitrag vom 21. Mär 2014
Antwort Antwort
Seite 1 von 2  1 2      
4dk2

Registriert seit: 4. Sep 2007
176 Beiträge
 
#1

[XE3] Operator Overloading, Verhalten?

  Alt 20. Mär 2014, 15:57
Delphi-Version: XE3
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.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.442 Beiträge
 
Delphi 12 Athens
 
#2

AW: [XE3] Operator Overloading, Verhalten?

  Alt 20. Mär 2014, 16:23
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
4dk2

Registriert seit: 4. Sep 2007
176 Beiträge
 
#3

AW: [XE3] Operator Overloading, Verhalten?

  Alt 20. Mär 2014, 16:43
Habs direkt mal getestet:

Delphi-Quellcode:

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' }
Also wird im lokalen Teil, nur der veränderte Wert übernommen.
"lg" hat ja immer noch den zugewiesenen Wert vor der Addition.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.580 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: [XE3] Operator Overloading, Verhalten?

  Alt 20. Mär 2014, 16:47
Ich denke eher das Verhalten bei localVar1 ist der Fehler.
Richtig, der Compiler "vergisst" an der Stelle den Aufruf von CopyRecord usw., so dass die Werte nicht überschrieben werden.
Bei den beiden anderen Varianten wird der Record nach dem Operator jeweils überschrieben.

Ich glaube auch nicht, dass das Absicht ist.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.033 Beiträge
 
Delphi 12 Athens
 
#5

AW: [XE3] Operator Overloading, Verhalten?

  Alt 20. Mär 2014, 17:19
Delphi-Quellcode:
class operator TVarX.implicit(const z: integer): TVarX;
begin
  Result.FormMaster := nil;
  Result.Value := z;
end;
Ohne FormMaster:=nil kann es sein, daß FormMaster einen undefinierten Zufallswert enthält. (nicht NIL)
Und nun fällt es auch auf, warum dein .object zwangsweise verschwinden muß.

Zitat:
Hab dann die Variable lokal angelegt, und einfach mit
v.object := irgendwas;
und
v:=100;
initialisiert.
Das ist auch richtig so, denn du weißt ja dem "kompletten" Record einen neuen Wert zu und alles was vorher drin stand, ist somit hinfällig.

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;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (20. Mär 2014 um 17:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.033 Beiträge
 
Delphi 12 Athens
 
#6

AW: [XE3] Operator Overloading, Verhalten?

  Alt 20. Mär 2014, 17:26
Ich denke eher das Verhalten bei localVar1 ist der Fehler.
Richtig, der Compiler "vergisst" an der Stelle den Aufruf von CopyRecord usw., so dass die Werte nicht überschrieben werden.
Bei den beiden anderen Varianten wird der Record nach dem Operator jeweils überschrieben.

Ich glaube auch nicht, dass das Absicht ist.
Rate mal, warum ich ständig predige, daß man ein Result "immer" vollständig initialisieren muß.

Delphi-Quellcode:
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;
Denn bei Records (über 8 bytes oder mit gemanageten Typen) und gemanageten Typen (Strings, Interfaces usw.) baut der Compiler das intern so um.
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;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (20. Mär 2014 um 17:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von JamesTKirk
JamesTKirk

Registriert seit: 9. Sep 2004
Ort: München
604 Beiträge
 
FreePascal / Lazarus
 
#7

AW: [XE3] Operator Overloading, Verhalten?

  Alt 21. Mär 2014, 07:34
Das Delphi das seit Delphi2006 schon kann war mir neu.
Und FPC kann das schon viel länger

Delphi-Quellcode:
class operator TVarX.implicit(const z: integer): TVarX;
begin
  result.Value := z;
end;
Das hier ist falsch. Ein Operator in Delphi ist implizit immer eine statische Funktion. Das heißt es gibt kein Self 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.

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
Sven
[Free Pascal Compiler Entwickler]
this post is printed on 100% recycled electrons
  Mit Zitat antworten Zitat
4dk2

Registriert seit: 4. Sep 2007
176 Beiträge
 
#8

AW: [XE3] Operator Overloading, Verhalten?

  Alt 21. Mär 2014, 08:25
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.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.442 Beiträge
 
Delphi 12 Athens
 
#9

AW: [XE3] Operator Overloading, Verhalten?

  Alt 21. Mär 2014, 08:31
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:
type
  TVarIntX = record
    Value: Integer;
    Objekt: TObject;
  end;
und in den Berechnungen nimmst du gleich v.Value anstatt TestInt .
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
4dk2

Registriert seit: 4. Sep 2007
176 Beiträge
 
#10

AW: [XE3] Operator Overloading, Verhalten?

  Alt 21. Mär 2014, 08:50
Entweder ist dein Beispiel schlecht konstruiert oder du siehst den Wald vor lauter Bäumen nicht.
Ist jetzt nicht das optimale Beispiel


Zitat:
und in den Berechnungen nimmst du gleich v.Value ...
Das will ich ja vermeiden.

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()
  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 10:27 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