RAD Studio (Common)
ContentsIndex
PreviousUpNext
Operator Overloading

This topic describes Delphi's operator methods and how to overload them.

Delphi for Win32 allows certain functions, or "operators" to be overloaded within record declarations. The name of the operator function maps to a symbolic representation in source code. For example, the Add operator maps to the + symbol. The compiler generates a call to the appropriate overload, matching the context (i.e. the return type, and type of parameters used in the call), to the signature of the operator function. The following table shows the Delphi operators that can be overloaded:

Operator 
Category 
Declaration Signature 
Symbol Mapping 
Implicit  
Conversion  
Implicit(a : type) : resultType;  
implicit typecast  
Explicit  
Conversion  
Explicit(a: type) : resultType;  
explicit typecast  
Negative  
Unary  
Negative(a: type) : resultType;  
-  
Positive  
Unary  
Positive(a: type): resultType;  
+  
Inc  
Unary  
Inc(a: type) : resultType;  
Inc  
Dec  
Unary  
Dec(a: type): resultType  
Dec  
LogicalNot  
Unary  
LogicalNot(a: type): resultType;  
not  
BitwiseNot  
Unary  
BitwiseNot(a: type): resultType;  
not  
Trunc  
Unary  
Trunc(a: type): resultType;  
Trunc  
Round  
Unary  
Round(a: type): resultType;  
Round  
Equal  
Comparison  
Equal(a: type; b: type) : Boolean;  
=  
NotEqual  
Comparison  
NotEqual(a: type; b: type): Boolean;  
<>  
GreaterThan  
Comparison  
GreaterThan(a: type; b: type) Boolean;  
>  
GreaterThanOrEqual  
Comparison  
GreaterThanOrEqual(a: type; b: type): resultType;  
>=  
LessThan  
Comparison  
LessThan(a: type; b: type): resultType;  
<  
LessThanOrEqual  
Comparison  
LessThanOrEqual(a: type; b: type): resultType;  
<=  
Add  
Binary  
Add(a: type; b: type): resultType;  
+  
Subtract  
Binary  
Subtract(a: type; b: type) : resultType;  
-  
Multiply  
Binary  
Multiply(a: type; b: type) : resultType;  
*  
Divide  
Binary  
Divide(a: type; b: type) : resultType;  
/  
IntDivide  
Binary  
IntDivide(a: type; b: type): resultType;  
div  
Modulus  
Binary  
Modulus(a: type; b: type): resultType;  
mod  
LeftShift  
Binary  
LeftShift(a: type; b: type): resultType;  
shl  
RightShift  
Binary  
RightShift(a: type; b: type): resultType;  
shr  
LogicalAnd  
Binary  
LogicalAnd(a: type; b: type): resultType;  
and  
LogicalOr  
Binary  
LogicalOr(a: type; b: type): resultType;  
or  
LogicalXor  
Binary  
LogicalXor(a: type; b: type): resultType;  
xor  
BitwiseAnd  
Binary  
BitwiseAnd(a: type; b: type): resultType;  
and  
BitwiseOr  
Binary  
BitwiseOr(a: type; b: type): resultType;  
or  
BitwiseXor  
Binary  
BitwiseXor(a: type; b: type): resultType;  
xor  

No operators other than those listed in the table may be defined on a class or record. 

Overloaded operator methods cannot be referred to by name in source code. To access a specific operator method of a specific class or record, you must use explicit typecasts on all of the operands. Operator identifiers are not included in the class or record's list of members.  

No assumptions are made regarding the distributive or commutative properties of the operation. For binary operators, the first parameter is always the left operand, and the second parameter is always the right operand. Associativity is assumed to be left-to-right in the absence of explicit parentheses.  

Resolution of operator methods is done over the union of accessible operators of the types used in the operation (note this includes inherited operators). For an operation involving two different types A and B, if type A has an implicit conversion to B, and B has an implicit conversion to A, an ambiguity will occur. Implicit conversions should be provided only where absolutely necessary, and reflexivity should be avoided. It is best to let type B implicitly convert itself to type A, and let type A have no knowledge of type B (or vice versa).  

As a general rule, operators should not modify their operands. Instead, return a new value, constructed by performing the operation on the parameters. 

Overloaded operators are used most often in records (i.e. value types).

Operator overloads are declared within classes or records, with the following syntax:

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;

Implementation of overloaded operators must also include the class operator syntax:

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;

The following are some examples of overloaded operators:

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

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

var
x, y: TMyClass;
begin
   x := 12;      // Implicit conversion from an Integer
   y := x + x;   // Calls TMyClass.Add(a, b: TMyClass): TMyClass
   b := b + 100; // Calls TMyClass.Add(b, TMyClass.Implicit(100))
end;
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!