[gelöst] Operatoren überladen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

[gelöst] Operatoren überladen

Beitrag von Scurra »

Hallo zusammen,

jetzt melde ich mich schon wieder mit einem Anfängerproblem. Ich habe inzwischen etwas über Klassen in Delphi gelesen. Da ich in anderen Programmiersprachen zum Üben z. B. eine Klasse für komplexe Zahlen geschrieben habe, möchte ich das jetzt auch mit Delphi machen. Ein wesentlicher Bestandteil ist es, Operationen wie z. B. die Addition zu überladen. Wie ich jedoch gelesen habe, ist es u. U. nicht möglich, Operatoren in Klassen zu überladen, sondern nur in records.

Ich habe das Überladen des Operators direkt in der Klasse versucht, etwa so (das ist meine Klassendeklaration):

Code: Alles auswählen

type
  TcomplxNbr = class
  private
    Freal : Double;
    Fim : Double;
  public
    constructor create; overload;
    constructor create(x, y : Double); overload;
    procedure setReal(x : Double);
    procedure setIm(y : Double);
    function getReal: Double;
    function getIm: Double;
 
    property real : Double read getReal write setReal;
    property im : Double read getIm write setIm;
 
    class operator add(a, b: TcomplxNbr): TcomplxNbr; // HIER TRITT EIN FEHLER AUF
  end;
In der Zeile, in der ich den Additions-Operator deklariere, tritt folgender Fehler auf: Procedure or Function expected

Wie ich schon oben erwähnt habe, liegt das wohl daran, dass man die Operatoren nicht in den Klassen, sondern nur in Records überladen kann.

Gibt es irgendeinen Trick bzw. eine Möglichkeit, die Klasse beizubehalten und die Operatoren trotzdem zu überladen?
Zuletzt geändert von Scurra am Mi 14. Jan 2015, 22:30, insgesamt 1-mal geändert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Operatoren überladen

Beitrag von m.fuchs »

Das liegt wohl daran, dass du den Operator da falsch deklarierst. Ein Beispiel für einen Operator auf einer Klasse:

Code: Alles auswählen

type
  TMyClass = class(TObject)
    private
      FText: String;
    public
      property Text: String read FText write FText;
  end;
 
operator + (m1, m2: TMyClass) m : TMyClass;
begin
  m := TMyClass.Create;
  m.Text := m1.Text + m2.Text;
end;
 
var
  x, y, z: TMyClass;
 
begin
  x := TMyClass.Create;
  x.Text := 'Hallo';
  y := TMyClass.Create;
  y.Text := ' du...';
  z := x + y;
  WriteLn(z.Text);
  ReadLn;
  FreeAndNil(x);
  FreeAndNil(y);
  FreeAndNil(z);
end.
 
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Operatoren überladen

Beitrag von Scurra »

Fehlt hier nicht die Deklaration des Operators?

Ich habe alles, was mit meiner Klasse TcomplxNbr zu tun hat, in eine eigene Unit geschrieben. Wenn ich dort den Operator definiere, dann gibt es keinen Fehler, aber wenn ich es in meiner Unit, die das Formular enthält, anwenden möchte, dann kommt in der Zeile, in der ich den Operator auf die komplexen Zahlen anwenden möchte folgender Fehler:

Operator is not overloaded "TcomplxNbr" + "TcomplxNbr"

Das wundert mich auch nicht, denn nach dem, was ich gelesen habe, ist der überladene Operator nur in der Unit sichtbar, in der ich ihn definiert habe, da der überladene Operator nicht im interface deklariert wurde.

Falls noch unklar ist, was ich gemacht habe:

Relevanter Quelltext in Unit1.pas (complxNbr.pas ist natürlich eingebunden):

Code: Alles auswählen

{...}
 
var
  Form1: TForm1;
  a, b, c: TcomplxNbr;
 
implementation
 
{$R *.lfm}
 
begin
 a := TcomplxNbr.create(2,4);
 b := TcomplxNbr.create(2,3);
 try
   c := a+b; // HIER TRITT EIN FEHLER AUF
 finally
   a.Free;
   b.Free;
 end;
 ShowMessage(FloatToStr(c.real) + ' +i*' + FloatToStr(c.im));
 
end.
Relevanter Quelltext in complxNbr.pas:

Code: Alles auswählen

unit complxNbr;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils;
 
type
  TcomplxNbr = class
  private
    Freal : Double;
    Fim : Double;
  public
    constructor create; overload;
    constructor create(x, y : Double); overload;
    procedure setReal(x : Double);
    procedure setIm(y : Double);
    function getReal: Double;
    function getIm: Double;
 
    property real : Double read getReal write setReal;
    property im : Double read getIm write setIm;
 
  end;
 
implementation
 
 { TcomplxNbr }
 
{...}
 
operator + (a, b: TComplxNbr): TComplxNbr;
begin
  result := TcomplxNbr.create(a.real + b.real, a.im + b.im);
end;
 
end.
Warum funktioniert das mit "class operator add..." eigentlich nicht? Ich habe mehrere Quellen im Internet gefunden, in denen das so beschrieben wird, z. B.
http://www.delphi-treff.de/tutorials/ob ... ratoren/2/
http://docs.embarcadero.com/products/ra ... s_xml.html

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Operatoren überladen

Beitrag von m.fuchs »

Scurra hat geschrieben:Fehlt hier nicht die Deklaration des Operators?
Nö, ist ja nur ein Programm und keine Unit.
Scurra hat geschrieben:Ich habe alles, was mit meiner Klasse TcomplxNbr zu tun hat, in eine eigene Unit geschrieben. Wenn ich dort den Operator definiere, dann gibt es keinen Fehler, aber wenn ich es in meiner Unit, die das Formular enthält, anwenden möchte, dann kommt in der Zeile, in der ich den Operator auf die komplexen Zahlen anwenden möchte folgender Fehler:
Operator is not overloaded "TcomplxNbr" + "TcomplxNbr"
Das liegt daran, dass dein neuer Operator nicht von außen sichtbar ist. Er steht ja nur im implementation - Teil.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Scurra
Beiträge: 29
Registriert: Mi 31. Dez 2014, 12:08

Re: Operatoren überladen

Beitrag von Scurra »

Das liegt daran, dass dein neuer Operator nicht von außen sichtbar ist. Er steht ja nur im implementation - Teil.
Eben, so wie ich es oben schon geschrieben habe.

Vorhin hatte ich wohl irgendeinen Tippfehler o. ä., denn ich konnte die Deklaration des überladenen Operators nicht in den interface-Teil schreiben (auch nicht außerhalb der Klasse complxNbr, wo die Deklaration hingehört). Aber jetzt klappt alles. Danke für deine Hilfe.

Eine Frage hätte ich aber trotzdem noch: Warum funktioniert es nicht, die Operatoren so zu überschreiben, wie es in den beiden Links in meinem letzten Beitrag beschrieben ist?

torte
Beiträge: 13
Registriert: Sa 9. Jun 2012, 08:45

Re: Operatoren überladen

Beitrag von torte »

Hallo,
du musst das Class vor deinem Operator wegnehmen.
Das mit dem class hat bei mir auch nicht so richtig funktioniert. Wenn ich es gelöscht habe hingegen, lief alles ohne Probleme.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Operatoren überladen

Beitrag von m.fuchs »

torte hat geschrieben:du musst das Class vor deinem Operator wegnehmen.
Das mit dem class hat bei mir auch nicht so richtig funktioniert. Wenn ich es gelöscht habe hingegen, lief alles ohne Probleme.
Könntest du das mal bitte als lauffähigen Beispielquellcode posten?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

marcov
Beiträge: 1102
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Operatoren überladen

Beitrag von marcov »

Scurra hat geschrieben: Eine Frage hätte ich aber trotzdem noch: Warum funktioniert es nicht, die Operatoren so zu überschreiben, wie es in den beiden Links in meinem letzten Beitrag beschrieben ist?
Free Pascal hat Operator-overloading zuerst implementiert. Jahre später ist auch Embarcadero mit eine eigene Syntax gekommen, die bis heute noch nicht implementiert ist.

diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Re: Operatoren überladen

Beitrag von diogenes »

Ich rate Dir, keine Klassen als Operanden zu nehmen, weil die Instanzen in Pascal nicht automatisch aus dem Speicher genommen werden, wenn nichts mehr auf sie vberwesit (sollte man mit einem Compilerschalter möglich machen, finde ich). Numm, wenn Du zu den Feldern einer records Methoden implementieren willst, den Typ object, ohne aber virtuelle Methoden zu deklarieren (nur nicht-virtuelle). Das funktioniert fast wie Klassen (Referenz: http://www.freepascal.org/docs-html/ref ... x61-680005 ) und entfernt nicht benötigte Daten zuverlässig aus dem Speicher.
Ceterum censeo computatores per Pascal docendos esse.

Socke
Lazarusforum e. V.
Beiträge: 3177
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: Operatoren überladen

Beitrag von Socke »

diogenes hat geschrieben:Ich rate Dir, keine Klassen als Operanden zu nehmen, weil die Instanzen in Pascal nicht automatisch aus dem Speicher genommen werden, wenn nichts mehr auf sie vberwesit (sollte man mit einem Compilerschalter möglich machen, finde ich).
Man kann die referenzgezählten Klasse TInterfacedObject verwenden.
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: Operatoren überladen

Beitrag von mschnell »

diogenes hat geschrieben: (sollte man mit einem Compilerschalter möglich machen, finde ich).
"Refererence Counted Objects" (die automatisch gefreed werden) wurden vor Kurzem in der Englischen Mailing Liste intensiv diskutiert, weil neue Delphi Versionen sie verwenden. Es stellt sich heraus, dass man damit sehr leicht Programm-Abstürze hervorrufen kann, wenn man bestimmte Operationen damit macht, die der Compiler nicht verhindern kann. Deshalb war der Tenor, sie nicht zu implementieren - obwohl der Compiler-Sourcecode dafür schon testweise erstellt wurde.

-Michael

torte
Beiträge: 13
Registriert: Sa 9. Jun 2012, 08:45

Re: [gelöst] Operatoren überladen

Beitrag von torte »

Ok,
hier noch mal ein kurzer Code dazu:

Code: Alles auswählen

constructor Create(AOwner: TComponent); override; overload;
      constructor Create(AOwner: TForm); overload;
funktioniert einwandfrei.
Hoffentlich hilft das.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: [gelöst] Operatoren überladen

Beitrag von m.fuchs »

Was hat das mit diesem Thema hier zu tun?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Antworten