Compago

...free knowledge

 
  • Increase font size
  • Default font size
  • Decrease font size
Home Manuali Programmazione Overloading degli operatori con Delphi

Overloading degli operatori con Delphi

E-mail Stampa PDF

Nelle versioni più recenti di Delphi è stata introdotta la possibilità di inserire dei metodi nei record ed anche di personalizzare gli operatori che agiscono sui record. In questo modo potremo sommare, sottrarre, comparare due variabili di un tipo di record creato da noi.
Prima di fare un esempio è meglio fare una piccola introduzione.

Gli operatori possono essere di quattro tipologie:

  • unari : tutte le operazione che hanno un solo operando ( negazione , incremento etc..)
  • binari : tutte le operazioni che hanno due operandi ( somma, moltiplicazione etc..)
  • di confronto : tutte le operazioni di confronto tra due operandi ( maggiore , minore etc...)
  • di conversione : i vari typecast

Dal un punto di vista della programmazione per dichiarare un record che ha degli operatori personalizzati deve seguire questo schema:

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;

Quando gli operatori dovranno essere implementati dovranno seguire quest'altro schema:

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;

Tra i vari parametri almeno uno deve essere del tipo di record che stiamo creando.

I vari operatori che potremo personalizzare sono questi:

Operatore Categoria Tipo di dichiarazione Simbolo Uso
Implicit Conversion Implicit(a : type) : resultType; implicit typecast R := A;
Explicit Conversion Explicit(a: type) : resultType; explicit typecast R := TValue(A);
Negative Unary Negative(a: type) : resultType; - R := -A
Positive Unary Positive(a: type): resultType; + R := +A
Inc Unary Inc(a: type) : resultType; Inc Inc(A);
Dec Unary Dec(a: type): resultType Dec Dec(A);
LogicalNot Unary LogicalNot(a: type): resultType; not R := not A;
BitwiseNot Unary BitwiseNot(a: type): resultType; not R := not A;
Trunc Unary Trunc(a: type): resultType; Trunc R := Trunc(A);
Round Unary Round(a: type): resultType; Round R := Round(A);
In Set In(a: type; b: type) : Boolean; in R := A in B;
Equal Comparison Equal(a: type; b: type) : Boolean; = R := A = B;
NotEqual Comparison NotEqual(a: type; b: type): Boolean; <> R := A <> B;
GreaterThan Comparison GreaterThan(a: type; b: type) Boolean; > R := A > B;
GreaterThanOrEqual Comparison GreaterThanOrEqual(a: type; b: type): Boolean; >= R := A >= B;
LessThan Comparison LessThan(a: type; b: type): Boolean; < R := A < B;
LessThanOrEqual Comparison LessThanOrEqual(a: type; b: type): Boolean; <= R := A <= B;
Add Binary Add(a: type; b: type): resultType; + R := A + B;
Subtract Binary Subtract(a: type; b: type) : resultType; - R := A - B;
Multiply Binary Multiply(a: type; b: type) : resultType; * R := A * B;
Divide Binary Divide(a: type; b: type) : resultType; / R := A / B;
IntDivide Binary IntDivide(a: type; b: type): resultType; div R := A div B;
Modulus Binary Modulus(a: type; b: type): resultType; mod R := A mod B;
LeftShift Binary LeftShift(a: type; b: type): resultType; shl R := A shl B;
RightShift Binary RightShift(a: type; b: type): resultType; shr R := A shr B;
LogicalAnd Binary LogicalAnd(a: type; b: type): resultType; and R := A and B;
LogicalOr Binary LogicalOr(a: type; b: type): resultType; or R := A or B;
LogicalXor Binary LogicalXor(a: type; b: type): resultType; xor R := A xor B;
BitwiseAnd Binary BitwiseAnd(a: type; b: type): resultType; and R := A and B;
BitwiseOr Binary BitwiseOr(a: type; b: type): resultType; or R := A or B;
BitwiseXor Binary BitwiseXor(a: type; b: type): resultType; xor R := A xor B;

A questo punto vediamo un esempio pratico. Creeremo una tipo di dato che dovrà rappresentare un numero complesso; in record quindi avrà due campi: uno per la parte reale e l'altro per la parte immaginaria.

unit UnitComplex;

interface

uses
SysUtils;
type
TComplex = record
R,I:double;
class operator Add(a, b: TComplex): TComplex; //permette la somma tra 2 variabili TComplex
class operator Add(a:string; b: TComplex): string; //permette la concatenazione tra una stringa e un TComplex
class operator Subtract(a, b: TComplex): TComplex; //permette la sottrazione tra e TComplex
class operator Multiply(a, b: TComplex): TComplex; //permette la moltiplicazione tra TComplex
class operator Divide(a, b: TComplex): TComplex; //permette la divisione tra TComplex
class operator Implicit(n: integer): TComplex; //gestisce la conversione da intero a Tcomplex
class operator Implicit(n: double): TComplex; //gestisce la conversione da double a Tcomplex
class operator Implicit(c: TComplex): integer; //gestisce la conversione da Tcomplex a intero
class operator Implicit(c: TComplex): double; //gestisce la conversione da Tcomplex a double
class operator Implicit(c: TComplex): string; //gestisce la conversione da Tcomplex a stringa di testo
end;

implementation

{ TComplex }

class operator TComplex.Add(a, b: TComplex): TComplex;
begin
result.R:=a.R+b.R;
result.I:=a.I+b.I;
end;

class operator TComplex.Add(a: string; b: TComplex): string;
begin
result:=a+string(b);
end;

class operator TComplex.Divide(a, b: TComplex): TComplex;
var
M:double;
begin
M:=(b.R*b.R)+(b.I*b.I);
result.R:=((a.R*b.R)+(a.I*b.I))/M;
result.I:=((a.I*b.R)-(a.R*b.I))/M;
end;

class operator TComplex.Implicit(c: TComplex): integer;
begin
Result:=round(c.R);
end;

class operator TComplex.Implicit(c: TComplex): double;
begin
Result:=c.R;
end;

class operator TComplex.Implicit(n: integer): TComplex;
begin
Result.R:=n;
Result.I:=0;
end;

class operator TComplex.Implicit(n: double): TComplex;
begin
Result.R:=n;
Result.I:=0;
end;

class operator TComplex.Multiply(a, b: TComplex): TComplex;
begin
result.R:=(a.R*b.R)-(a.I*b.I);
result.I:=(a.R*b.I)+(a.I*b.R);
end;

class operator TComplex.Subtract(a, b: TComplex): TComplex;
begin
result.R:=a.R-b.R;
result.I:=a.I-b.I;
end;

class operator TComplex.Implicit(c: TComplex): string;
begin
if c.I=0 then
result:=Format('%g',[c.R])
else if c.R=0 then
result:=Format('%gi',[c.I])
else if c.I>0 then
result:=Format('%g+%gi',[c.R,c.I])
else
result:=Format('%g%gi',[c.R,c.I]);
end;

end.

Come abbiamo detto il nuovo tipo di dati ha due campi (R e I) e poi seguono una serie di metodi che servono per descrivere i vari operatori che andranno ad interagire col nuovo tipo.

Per vedere come funziona vediamo un esempio:

var
a,b,c:Tcomplex;
n:integer;
begin
a.R:=1;
a.I:=2;
writeln('a = '+a); // chiama l'operatore Add(a:string; b: TComplex): string;
b.R:=-1.5;
b.I:=3.2;
writeln('b = '+b);
writeln(a+b); // chiama l'operatore Implicit( Add(a, b: TComplex): TComplex): string;
writeln(2*a-b);
writelna*b);
writeln(a/b);
end;

Naturalmente questo è solo un piccolo esempio e il tipo TComplex potrebbe essere implementato molto meglio, ma l'overloading degli operatori potrebbe facilitare non poco la scrittura e la comprensione di programmi. Purtroppo l'overloading degli operatori per ora è permessa solo con i record e non con le classi ( in .net anche per le classi).

Ultimo aggiornamento ( Sabato 31 Luglio 2010 10:23 )  
Loading

Login