DMarlon Studio

Lección 15 · 15 de 20

Sobrecarga de operadores · Pascal

Defina +, * y conversiones para sus propios tipos con advanced records en Free Pascal: un tipo dinero en céntimos que se suma como un número.

Pascal · Sobrecarga de operadores en DMarlon Studio: el código del ejemplo y su salida en la terminal

La directiva `{$modeswitch advancedrecords}` permite que un record tenga métodos y operadores, como una clase pequeña pero sin Create ni Free: es un valor que se copia al asignarlo. TMoney guarda el importe en céntimos enteros (Int64) para que las sumas de dinero no arrastren errores de redondeo.

Cada `class operator` enseña al compilador a usar un operador con el tipo. + suma dos TMoney y * multiplica un TMoney por una cantidad entera. Se implementan como funciones: reciben los operandos y devuelven el resultado en Result.

El más curioso es `:=`, el operador de conversión implícita: dice cómo convertir un Double en TMoney, redondeando a céntimos. Gracias a él, coffee := 1.60 funciona, y en coffee * 2 + 3.25 el 3.25 se convierte solo para poder usar el + de TMoney.

ToString es un método normal del record. `WriteStr` funciona como WriteLn pero escribe en una cadena, con el mismo formato :0:2, y no necesita la unidad SysUtils. El resultado se lee como una cuenta de cafetería: dos cafés y un pastel, 6.45 EUR.

Código · main.pas

program main;{$modeswitch advancedrecords}type  TMoney = record    Cents: Int64;  // whole cents: no rounding surprises    class operator :=(euros: Double): TMoney;    class operator +(a, b: TMoney): TMoney;    class operator *(a: TMoney; qty: Integer): TMoney;    function ToString: String;  end;class operator TMoney.:=(euros: Double): TMoney;begin  Result.Cents := Round(euros * 100);end;class operator TMoney.+(a, b: TMoney): TMoney;begin  Result.Cents := a.Cents + b.Cents;end;class operator TMoney.*(a: TMoney; qty: Integer): TMoney;begin  Result.Cents := a.Cents * qty;end;function TMoney.ToString: String;begin  WriteStr(Result, Cents / 100:0:2, ' EUR');  // like WriteLn, into a stringend;var coffee, bill: TMoney;begin  coffee := 1.60;             // := turns a Double into a TMoney  bill := coffee * 2 + 3.25;  // *, then + (3.25 is converted too)  WriteLn('Coffee: ', coffee.ToString, ' (', coffee.Cents, ' cents)');  WriteLn('2 coffees + 1 cake: ', bill.ToString);end.

Salida · fpc main.pas && ./main

Coffee: 1.60 EUR (160 cents)
2 coffees + 1 cake: 6.45 EUR

Para recordar

  • {$modeswitch advancedrecords} da métodos y operadores a los records.
  • class operator + define qué hace + con su tipo.
  • class operator := define una conversión implícita.
  • Un record es un valor: se copia, no se crea ni se libera.
  • Guarde el dinero en céntimos enteros.

Ejercicio

Añada class operator <(a, b: TMoney): Boolean y úselo para escribir si la cuenta supera los 5 EUR; después añada - para aplicar un descuento de 0.50.