DMarlon Studio

Lección 4 · 4 de 20

Métodos virtuales y polimorfismo · Pascal

Use virtual y override en Object Pascal para que cada clase responda a su manera a la misma llamada: polimorfismo con tarifas de envío.

Pascal · Métodos virtuales y polimorfismo en DMarlon Studio: el código del ejemplo y su salida en la terminal

Un método `virtual` puede ser sustituido por las clases hijas. TShipping.Cost calcula la tarifa normal (4.95 EUR más 0.80 por kilo), y TExpress y TPickup lo redefinen con `override`: misma firma, otro cálculo.

Dentro de un override se puede reutilizar el original: TExpress.Cost devuelve inherited Cost(kg) * 2, el doble de la tarifa normal, sin copiar la fórmula. TPickup.Cost devuelve 0, porque el cliente recoge el paquete en la tienda.

El bucle es donde aparece el polimorfismo: la variable option es de tipo TShipping, pero en cada vuelta contiene un objeto de otra clase. Como Cost es virtual, option.Cost(3.5) decide en tiempo de ejecución qué versión llamar según el objeto real, y salen tres precios distintos.

Sin virtual, el compilador elegiría por el tipo de la variable y las tres líneas costarían 7.75. El bucle recorre directamente la lista [TShipping.Create, TExpress.Create, TPickup.Create] y libera cada objeto en cuanto lo ha usado.

Es el mecanismo que mueve Lazarus: un formulario llama a Paint o Resize de cada control sin saber de qué clase es. En DMarlon Studio puede ejecutar este ejemplo con el destino Consola y la tecla F9.

Código · main.pas

program main;type  TShipping = class    function Cost(kg: Double): Double; virtual;  end;  TExpress = class(TShipping)    function Cost(kg: Double): Double; override;  end;  TPickup = class(TShipping)    function Cost(kg: Double): Double; override;  end;function TShipping.Cost(kg: Double): Double;begin  Result := 4.95 + 0.80 * kg;  // standard rateend;function TExpress.Cost(kg: Double): Double;begin  Result := inherited Cost(kg) * 2;  // twice the standard rateend;function TPickup.Cost(kg: Double): Double;begin  Result := 0;  // collected at the shopend;var option: TShipping;begin  for option in [TShipping.Create, TExpress.Create, TPickup.Create] do  begin    WriteLn(option.ClassName:10, ': ', option.Cost(3.5):5:2, ' EUR for 3.5 kg');    option.Free;  end;end.

Salida · fpc main.pas && ./main

 TShipping:  7.75 EUR for 3.5 kg
  TExpress: 15.50 EUR for 3.5 kg
   TPickup:  0.00 EUR for 3.5 kg

Para recordar

  • virtual permite que las hijas cambien el método; override lo cambia.
  • La versión que se ejecuta depende del objeto, no de la variable.
  • inherited dentro de un override reutiliza el original.
  • Una variable de la clase madre puede contener cualquier hija.
  • Sin virtual, no hay polimorfismo.

Ejercicio

Añada TInternational = class(TShipping) cuyo Cost sea la tarifa normal más 12 EUR de aduana, y métala en la lista del bucle.