Überladene Operatoren (Object Pascal)

Aus Appmethod Topics
Wechseln zu: Navigation, Suche

Nach oben zu Klassen und Objekte - Index


Dieses Thema beschreibt Operatormethoden von Object Pascal und wie sie überladen werden.

Allgemeines zum Überladen von Operatoren

Object Pascal für Win32 ermöglicht es, bestimmte Funktionen, auch "Operatoren" genannt, innerhalb von Record-Deklarationen zu überladen. Der Name der Operatorfunktion wird dabei einem Symbol im Quelltext zugeordnet. Beispielsweise entspricht das Symbol + dem Operator Add.

Der Compiler vergleicht den jeweiligen Kontext (Rückgabetyp und Typ der im Aufruf verwendeten Parameter) mit der Signatur der Operatorfunktion, und ruft den entsprechenden überladenen Operator auf.

Die folgende Tabelle enthält die Object Pascal-Operatoren, die überladen werden können:

Operator Kategorie Deklarationssignatur Symbolzuordnung

Implicit

Konvertierung

Implicit(a : Typ): Ergebnistyp;

Implizite Typumwandlung

Explicit

Konvertierung

Explicit(a: Typ): Ergebnistyp;

Explizite Typumwandlung

Negative

Unär

Negative(a: Typ): Ergebnistyp;

-

Positive

Unär

Positive(a: Typ): Ergebnistyp;

+

Inc

Unär

Inc(a: Typ): Ergebnistyp;

Inc

Dec

Unär

Dec(a: Typ): Ergebnistyp

Dec

LogicalNot

Unär

LogicalNot(a: Typ): Ergebnistyp;

not

Trunc

Unär

Trunc(a: Typ): Ergebnistyp;

Trunc

Round

Unär

Round(a: Typ): Ergebnistyp;

Round

In

Menge

In(a: Typ; b: Typ): Boolean;

in

Equal

Vergleich

Equal(a: Typ; b: Typ): Boolean;

=

NotEqual

Vergleich

NotEqual(a: Typ; b: Typ): Boolean;

<>

GreaterThan

Vergleich

GreaterThan(a: Typ; b: type) Boolean;

>

GreaterThanOrEqual

Vergleich

GreaterThanOrEqual(a: Typ; b: Typ): Boolean;

>=

LessThan

Vergleich

LessThan(a: Typ; b: Typ): Boolean;

<

LessThanOrEqual

Vergleich

LessThanOrEqual(a: Typ; b: Typ): Boolean;

<=

Add

Binär

Add(a: Typ; b: Typ): Ergebnistyp;

+

Subtract

Binär

Subtract(a: Typ; b: Typ): Ergebnistyp;

-

Multiply

Binär

Multiply(a: Typ; b: Typ): Ergebnistyp;

*

Divide

Binär

Divide(a: Typ; b: Typ): Ergebnistyp;

/

IntDivide

Binär

IntDivide(a: Typ; b: Typ): Ergebnistyp;

div

Modulus

Binär

Modulus(a: Typ; b: Typ): Ergebnistyp;

mod

LeftShift

Binär

LeftShift(a: Typ; b: Typ): Ergebnistyp;

shl

RightShift

Binär

RightShift(a: Typ; b: Typ): Ergebnistyp;

shr

LogicalAnd

Binär

LogicalAnd(a: Typ; b: Typ): Ergebnistyp;

and

LogicalOr

Binär

LogicalOr(a: Typ; b: Typ): Ergebnistyp;

or

LogicalXor

Binär

LogicalXor(a: Typ; b: Typ): Ergebnistyp;

xor

BitwiseAnd

Binär

BitwiseAnd(a: Typ; b: Typ): Ergebnistyp;

and

BitwiseOr

Binär

BitwiseOr(a: Typ; b: Typ): Ergebnistyp;

or

BitwiseXor

Binär

BitwiseXor(a: Typ; b: Typ): Ergebnistyp;

xor


Nur die in der Tabelle aufgeführten Operatoren können für eine Klasse oder einen Record definiert werden.

Es ist nicht möglich, eine überladene Operatormethode im Quelltext per Name zu referenzieren. Für den Zugriff auf eine bestimmte Operatormethode einer bestimmten Klasse oder eines Records siehe: Codebeispiel:OpOverloads_(Object Pascal). Operatorbezeichner sind für Klassen und Records in der Methodenliste der Klasse oder des Records aufgeführt und beginnen mit dem Wort "operator" (Beispiel: Methoden von System.AnsiStringBase). Sie können jeden der oben aufgeführten Operatoren in Ihre eigenen Klassen und Records implementieren.

Der Compiler verwendet unter den folgenden Voraussetzungen einen Operator für eine Klasse oder einen Record:

  • Bei Binäroperatoren muss ein Eingabeparameter der Klassentyp sein.
  • Bei Unäroperatoren muss der Eingabeparameter oder der Rückgabewert der Klassentyp sein.
  • Bei einem logischen Operator und einem bitweisen Operator mit demselben Symbol wird der logische Operator nur verwendet, wenn die Operanden boolesche Typen sind. Da der Typ der Klasse dieses Klassenoperators nicht boolesch ist, wird ein logischer Operator nur verwendet, wenn der andere Operand ein boolescher Typ ist.

Es bestehen keine Anforderungen bezüglich der distributiven oder kommutativen Eigenschaften der Operation. Bei binären Operatoren ist der erste Parameter immer der linke Operand und der zweite Parameter immer der rechte Operand. Sind keine Klammern vorhanden, erfolgt die Auswertung von links nach rechts.

Die Zuordnung von Operatormethoden erfolgt mittels der verfügbaren Operatoren der in der Operation verwendeten Typen (dies gilt auch für geerbte Operatoren). Wenn eine Operation mit den zwei unterschiedlichen Typen A und B für Typ A eine implizite Umwandlung in Typ B (und umgekehrt) vorsieht, ist keine Eindeutigkeit gegeben. Implizite Umwandlungen sollten nur - wenn unbedingt nötig - vorgenommen werden. Reflexivität ist zu vermeiden. Es ist am besten, eine implizite Umwandlung von Typ B in Typ A zu veranlassen und Typ A ohne Kenntnis von Typ B zu belassen (oder umgekehrt).

Grundsätzlich dürfen Operatoren ihre Operanden nicht verändern. Stattdessen muss ein neuer Wert zurückgegeben werden, der sich aus der Durchführung der Operation für die Parameter ergibt.

Überladene Operatoren werden meist in Records (Werttypen) verwendet.

Überladene Operatoren deklarieren

Überladene Operatoren werden in Klassen oder Records mit der folgenden Syntax deklariert:

type
   typeName = record
       class operator conversionOp(a: type): resultType;
       class operator unaryOp(a: type): resultType;
       class operator comparisonOp(a: type; b: type): Boolean;
       class operator binaryOp(a: type; b: type): resultType;
   end;

In der Implementierung überladener Operatoren muss auch die class operator-Syntax verwendet werden:

class operator typeName.conversionOp(a: type): resultType;
class operator typeName.unaryOp(a: type): resultType;
class operator typeName.comparisonOp(a: type; b: type): Boolean;
class operator typeName.binaryOp(a: type; b: type): resultType;

Nachstehend finden Sie einige Beispiele für überladene Operatoren:

type
   TMyRecord = record
     class operator Add(a, b: TMyRecord): TMyRecord;      // Addition of two operands of type TMyRecord
     class operator Subtract(a, b: TMyRecord): TMyRecord; // Subtraction of type TMyRecord
     class operator Implicit(a: Integer): TMyRecord;      // Implicit conversion of an Integer to type TMyRecord
     class operator Implicit(a: TMyRecord): Integer;      // Implicit conversion of TMyRecordto Integer
     class operator Explicit(a: Double): TMyRecord;       // Explicit conversion of a Double to TMyRecord
   end;

// Example implementation of Add
class operator TMyRecord.Add(a, b: TMyRecord): TMyRecord;
begin
   // ...
end;

var
x, y: TMyRecord;
begin
   x := 12;      // Implicit conversion from an Integer
   y := x + x;   // Calls TMyRecord.Add(a, b: TMyRecord): TMyRecord
   b := b + 100; // Calls TMyRecord.Add(b, TMyRecord.Implicit(100))
end;

Siehe auch

Codebeispiele