DMarlon Studio

Lesson 4 · 4 of 20

Virtual methods and polymorphism · Pascal

Use virtual and override in Object Pascal so each class answers the same call in its own way: polymorphism with shipping rates.

Pascal · Virtual methods and polymorphism in DMarlon Studio: the example's code and its output in the terminal

A `virtual` method can be replaced by child classes. TShipping.Cost works out the standard rate (4.95 EUR plus 0.80 per kilo), and TExpress and TPickup redefine it with `override`: same signature, different calculation.

Inside an override you can reuse the original: TExpress.Cost returns inherited Cost(kg) * 2, twice the standard rate, without copying the formula. TPickup.Cost returns 0, since the customer collects the parcel at the shop.

The loop is where polymorphism shows up: option is declared as TShipping, yet each pass it holds an object of a different class. Because Cost is virtual, option.Cost(3.5) decides at run time which version to call based on the real object, and three different prices come out.

Without virtual, the compiler would pick by the variable's type and all three lines would cost 7.75. The loop walks straight over the list [TShipping.Create, TExpress.Create, TPickup.Create] and frees each object as soon as it has been used.

This is the mechanism Lazarus runs on: a form calls Paint or Resize on every control without knowing its class. In DMarlon Studio you can run this example with the Console target and F9.

Code · 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.

Output · 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

Key points

  • virtual lets children change a method; override changes it.
  • The version that runs depends on the object, not the variable.
  • inherited inside an override reuses the original.
  • A parent-class variable can hold any child.
  • No virtual, no polymorphism.

Exercise

Add TInternational = class(TShipping) whose Cost is the standard rate plus 12 EUR in customs, and put it in the loop's list.