Operator overloading, or the ability to provide new implementations for built-in operators (such as '+', '-', '*' and '/') when the operands are user-defined types, is a new feature added to the Delphi language as of Delphi 8 (also known as Delphi.NET). This language feature is available in other languages such as C++ and C#. Those already familiar with how operator overloading is done in C# should have little trouble learning how operator overloading works in Delphi since the semantics are quite similar.
The point of operator overloading is to be able to provide a more intuitive way to use a class. For example, given a class TComplexNumber to represent complex numbers, it would be possible to define addition, subtraction, multiplication and division operations on complex numbers as follows:
TComplexNumber = class
strict private
FReal: Double;
FImaginary: Double;
public
constructor Create(const Real, Imaginary: Double);
function Add(const AValue: TComplexNumber): TComplexNumber;
function Subtract(const AValue: TComplexNumber): TComplexNumber;
function Multiply(const AValue: TComplexNumber): TComplexNumber;
function Divide(const AValue: TComplexNumber): TComplexNumber;
property Real: Double read FReal write FReal;
property Imaginary: Double read FImaginary write FImaginary;
end;
Given the above class declaration, one could use the class to do complex number arithmetic as follows:
var
A, B, C: TComplexNumber;
begin
A := TComplexNumber.Create(9, 3);
B := TComplexNumber.Create(7, 5);
C := A.Add(B); // adds A and B, assigns result to C
C := A.Subtract(B); // subtracts B from A, assigns result to C
C := A.Multiply(B); // multiplies A and B, assigns result to C
C := A.Divide(B); // divides A by B, assigns result to C
end.
This works but the way the code is written is not very intuitive. For example, it would be more intuitive to add A and B using the syntax 'A + B' rather than 'A.Add(B)'. In a similar fashion, it would be more intuitive to use the '-', '*' and '/' operators to perform subtraction, multiplication and division respectively, rather than having to use the 'Subtract', 'Multiply' and 'Divide' methods to do those same tasks.
This is where operator overloading comes in. Through operator overloading, it becomes possible for the author of the class to define implementations for operations wherein the class is an operand. Conversion, unary, comparison and binary operators can be overloaded. For a full list of overloadable operators and their corresponding declaration signatures, search for "Operator Overloads" in the Delphi.NET help.
Operator overloads in Delphi.NET are class (also known as "static") members and are declared using the operator keyword. The syntax is as follows (copied from the Delphi.NET help):
type
typeName = [class | 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;
The 'class operator' syntax should be used in the implementation of the overloaded operators as well. For example (taken from the Delphi.NET help):
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;
Returning to the complex numbers example, to re-define the TComplexNumber class to use operator overloading instead of function calls to do arithmetic, it could be re-written as follows:
TComplexNumber = class
strict private
FReal: Double;
FImaginary: Double;
public
constructor Create(const Real, Imaginary: Double);
class operator Add(const X, Y: TComplexNumber): TComplexNumber;
class operator Subtract(const X, Y: TComplexNumber): TComplexNumber;
class operator Multiply(const X, Y: TComplexNumber): TComplexNumber;
class operator Divide(const X, Y: TComplexNumber): TComplexNumber;
property Real: Double read FReal write FReal;
property Imaginary: Double read FImaginary write FImaginary;
end;
Having re-declared the class to use overloaded operators instead of functions, it then becomes possible to do complex number arithmetic as follows:
var
A, B, C: TComplexNumber;
begin
A := TComplexNumber.Create(9, 3);
B := TComplexNumber.Create(7, 5);
C := A + B; // adds A and B, assigns result to C
C := A - B; // subtracts B from A, assigns result to C
C := A * B; // multiplies A and B, assigns result to C
C := A / B; // divides A by B, assigns result to C
end.
Using operator overloading, complex number arithmetic is now more intuitive and it makes the code clearer and easier to read.
Here is the full source for the TComplexNumber class as well as an example project showing its usage:
ComplexNumber.pas:
unit ComplexNumber;
interface
type
TComplexNumber = class
strict private
FReal: Double;
FImaginary: Double;
strict protected
function Conjugate: TComplexNumber;
public
constructor Create(const Real, Imaginary: Double);
class operator Add(const X, Y: TComplexNumber): TComplexNumber;
class operator Subtract(const X, Y: TComplexNumber): TComplexNumber;
class operator Multiply(const X, Y: TComplexNumber): TComplexNumber;
class operator Divide(const X, Y: TComplexNumber): TComplexNumber;
function ToString: string; override;
property Real: Double read FReal write FReal;
property Imaginary: Double read FImaginary write FImaginary;
end;
implementation
uses
SysUtils;
{ TComplexNumber }
function TComplexNumber.Conjugate: TComplexNumber;
begin
Result := TComplexNumber.Create(FReal, FImaginary * -1);
end;
constructor TComplexNumber.Create(const Real, Imaginary: Double);
begin
inherited Create;
FReal := Real;
FImaginary := Imaginary;
end;
class operator TComplexNumber.Add(const X,
Y: TComplexNumber): TComplexNumber;
begin
Result := TComplexNumber.Create(X.Real + Y.Real, X.Imaginary + Y.Imaginary);
end;
class operator TComplexNumber.Subtract(const X,
Y: TComplexNumber): TComplexNumber;
begin
Result := TComplexNumber.Create(X.Real - Y.Real, X.Imaginary - Y.Imaginary);
end;
class operator TComplexNumber.Multiply(const X,
Y: TComplexNumber): TComplexNumber;
begin
Result := TComplexNumber.Create((X.Real * Y.Real - X.Imaginary * Y.Imaginary),
(X.Real * Y.Imaginary + X.Imaginary * Y.Real));
end;
class operator TComplexNumber.Divide(const X,
Y: TComplexNumber): TComplexNumber;
begin
Result := TComplexNumber.Create((X * Y.Conjugate).Real / (Y * Y.Conjugate).Real,
(X * Y.Conjugate).Imaginary / (Y * Y.Conjugate).Real);
end;
function TComplexNumber.ToString: string;
begin
if (Imaginary > 0) then
Result := Format('%f+%fi', [FReal, FImaginary])
else
Result := Format('%f%fi', [FReal, FImaginary]);
end;
end.
Project1.dpr:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
ComplexNumber in 'ComplexNumber.pas';
var
A, B: TComplexNumber;
begin
A := TComplexNumber.Create(9, 3);
B := TComplexNumber.Create(7, 5);
WriteLn(Format('A = (%s), B = (%s)', [A, B]));
WriteLn(Format('A + B = (%s)', [A + B]));
WriteLn(Format('A - B = (%s)', [A - B]));
WriteLn(Format('A * B = (%s)', [A * B]));
WriteLn(Format('A / B = (%s)', [A / B]));
end.
This should produce the following output:
[d:\source\delphi.net\code\tcomplexnumber]Project1.exe
A = (9.00+3.00i), B = (7.00+5.00i)
A + B = (16.00+8.00i)
A - B = (2.00-2.00i)
A * B = (48.00+66.00i)
A / B = (1.05-0.32i)
[d:\source\delphi.net\code\tcomplexnumber]
Last updated on 2004-05-11.