Delphi : Surcharge Opérateurs

A propos de la surcharge d'opérateurs 

Delphi pour Win32 autorisent la surcharge de certaines fonctions (ou "opérateurs") dans les déclarations d'enregistrement. Le nom de la fonction opérateur correspond à une représentation symbolique dans le code source. Par exemple, l'opérateur Add correspond au symbole +. Le compilateur génère un appel à la surcharge appropriée, en faisant correspondre le contexte (c'est-à-dire le type de retour et le type des paramètres utilisés dans l'appel) à la signature de la fonction opérateur. Le tableau suivant énumère les opérateurs Delphi pouvant être surchargés :

Opérateur 
Catégorie 
Signature de déclaration 
Mappage de symbole 
Implicit  
Conversion  
Implicit(a : type): resultType;  
implicit typecast  
Explicit  
Conversion  
Explicit(a: type): resultType;  
explicit typecast  
Negative  
Unaire  
Negative(a: type): resultType;  
-  
Positive  
Unaire  
Positive(a: type): resultType;  
+  
Inc  
Unaire  
Inc(a: type): resultType;  
Inc  
Dec  
Unaire  
Dec(a: type): resultType  
Dec  
LogicalNot  
Unaire  
LogicalNot(a: type): resultType;  
not  
BitwiseNot  
Unaire  
BitwiseNot(a: type): resultType;  
not  
Trunc  
Unaire  
Trunc(a: type): resultType;  
Trunc  
Round  
Unaire  
Round(a: type): resultType;  
Round  
Equal  
Comparaison 
Equal(a: type; b: type): Boolean;  
=  
NotEqual  
Comparaison 
NotEqual(a: type; b: type): Boolean;  
<>  
GreaterThan  
Comparaison 
GreaterThan(a: type; b: type) Boolean;  
>  
GreaterThanOrEqual  
Comparaison 
GreaterThanOrEqual(a: type; b: type): resultType;  
>=  
LessThan  
Comparaison 
LessThan(a: type; b: type): resultType;  
<  
LessThanOrEqual  
Comparaison 
LessThanOrEqual(a: type; b: type): resultType;  
<=  
Add  
Binaire  
Add(a: type; b: type): resultType;  
+  
Subtract  
Binaire  
Subtract(a: type; b: type): resultType;  
-  
Multiply  
Binaire  
Multiply(a: type; b: type): resultType;  
*  
Divide  
Binaire  
Divide(a: type; b: type): resultType;  
/  
IntDivide  
Binaire  
IntDivide(a: type; b: type): resultType;  
div  
Modulus  
Binaire  
Modulus(a: type; b: type): resultType;  
mod  
LeftShift  
Binaire  
LeftShift(a: type; b: type): resultType;  
shl  
RightShift  
Binaire  
RightShift(a: type; b: type): resultType;  
shr  
LogicalAnd  
Binaire  
LogicalAnd(a: type; b: type): resultType;  
and  
LogicalOr  
Binaire  
LogicalOr(a: type; b: type): resultType;  
or  
LogicalXor  
Binaire  
LogicalXor(a: type; b: type): resultType;  
xor  
BitwiseAnd  
Binaire  
BitwiseAnd(a: type; b: type): resultType;  
and  
BitwiseOr  
Binaire  
BitwiseOr(a: type; b: type): resultType;  
or  
BitwiseXor  
Binaire  
BitwiseXor(a: type; b: type): resultType;  
xor  


Aucun opérateur autre que ceux de ce tableau ne peut être défini sur une classe ou un enregistrement. 
Les méthodes d'opérateurs surchargés ne peuvent pas être référencées par nom dans le code source. Pour accéder à une méthode d'opérateur spécifique d'une classe ou d'un enregistrement spécifique, vous devez utiliser des transtypages explicites sur tous les opérandes. La liste des membres d'une classe ou d'un enregistrement ne comporte pas d'identificateur d'opérateur.  
Il n'existe aucune hypothèse concernant les propriétés distributives ou commutatives de l'opération. Pour les opérateurs binaires, le premier paramètre est toujours l'opérande gauche et le second paramètre l'opérande droit. En l'absence de parenthèses explicites, l'associativité est supposée être de gauche à droite.  
La résolution des méthodes d'opérateurs s'effectue par l'union d'opérateurs accessibles des types utilisés dans l'opération (y compris les opérateurs inherited). Pour une opération impliquant deux types différents (A et B), si le type A a une conversion implicite en B et B a une conversion implicite en A, cela entraîne une ambiguïté. Les conversions implicites ne doivent intervenir que lorsque cela est absolument nécessaire, et la réflexivité doit être évitée. Il est préférable de laisser le type B se convertir implicitement lui-même en type A et laisser le type A n'avoir aucune connaissance du type B (ou vice versa).  
En règle générale, les opérateurs ne doivent pas modifier leurs opérandes. A la place, ils renvoient une nouvelle valeur, construite en effectuant l'opération sur les paramètres. 
Les opérateurs surchargés sont utilisés plus souvent dans les enregistrements (c'est-à-dire les types de valeur). 

Déclaration des surcharges d'opérateurs

Les surcharges d'opérateurs sont déclarées dans des classes ou des enregistrements avec la syntaxe suivante :
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;
L'implémentation des opérateurs surchargés doit aussi inclure la syntaxe class operator :
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;
 
Voici quelques exemples d'opérateurs surchargés :
type
   TMyClass = class
     // Ajout de deux opérandes de type TMyClass
     class operator Add(a, b: TMyClass): TMyClass;     
     // Soustraction de type TMyClass
     class operator Subtract(a, b: TMyClass): TMyclass; 
     // Conversion implicite d'un entier en type TMyClass
     class operator Implicit(a: Integer): TMyClass;     
     // Conversion implicite de TMyClass en Integer
     class operator Implicit(a: TMyClass): Integer;     
     // Conversion explicite d'un double en type TMyClass
     class operator Explicit(a: Double): TMyClass;     
   end;

// Exemple d'implémentation de Add
class operator TMyClass.Add(a, b: TMyClass): TMyClass;
begin
   // ...
end;

var
x, y: TMyClass;
begin
   x := 12;      // Conversion implicite à partir d'un Integer
   y := x + x;   // Appelle TMyClass.Add(a, b: TMyClass): TMyClass
   b := b + 100; // Appelle TMyClass.Add(b, TMyClass.Implicit(100))
end;

1 commentaire:

Alex a dit…

Désolé mais ça ne fonctionne pas sur les classes. Seulement sur les record.