Inheritance

Our first example of inheritance, DerivedClassDemo, is developed from program ClassDemo on the previous page. This demonstration shows the syntax for creating from the base class Player a derived class ConfidentPlayer. We have a new function Pick in the base class, which will be overridden in an object of type ConfidentPlayer by its own (more favourable) function with the same identifier. The field Msg, the function GetMsg and the procedure Intro in the derived class are not present in the base class.

The purpose of a constructor is to perform initialisation. ConfidentPlayer has a constructor to initialise Msg.
program DerivedClassDemo;
  {$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TPlayer = class(TObject)
  private
    Name: string;
    Points: integer;
  public
    procedure SetName(Playername: string);
    function GetName: string;
    procedure AddPoints (NewPoints: integer);
    procedure ShowPoints;
    function GetPoints: real;
    function Pick: integer;
  end;

  TConfidentPlayer = class(TPlayer)
  private
    Msg: string;
  public
    constructor Create(InputMsg: string);
    function Pick: integer;
    procedure Intro;
    function GetMsg: string;
  end;

var
  Player1: TPlayer;
  Player2: TConfidentPlayer;
  Random1, Random2, i: integer;
  Name: string;

procedure TPlayer.AddPoints(NewPoints: integer);
begin
  Points := Points + NewPoints;
end;

procedure TPlayer.ShowPoints;
begin
  writeln('Points for ', Name ,': ', Points);
end;

procedure TPlayer.SetName(PlayerName : string);
begin
  PlayerName := lowerCase(PlayerName);
  PlayerName[1] := upCase(PlayerName[1]);
  Name := PlayerName;
end;

function TPlayer.GetName : string;
begin
  result := Name;
end;

function TPlayer.GetPoints: real;
begin
  result := Points;
end;

function TPlayer.Pick: integer;
begin
  result := random(4);
end;

constructor TConfidentPlayer.Create(InputMsg: string);
begin
  Msg := InputMsg;
end;

procedure TConfidentPlayer.Intro;
begin
  writeln('Hi! My name is ', Name, '. ', GetMsg);
end;

function TConfidentPlayer.GetMsg: string;
begin
  result := Msg;
end;

function TConfidentPlayer.Pick : integer;
begin
  result := random(3) + 1;
end;

begin
  Player1 := TPlayer.Create;
  write('Please enter the forename of the first player. ');
  readln(Name);
  Player1.SetName(Name);
  Player2 := TConfidentPlayer.Create('I feel lucky.');
  write('Please enter the forename of the second player. ');
  readln(Name);
  Player2.SetName(Name);
  Player2.Intro;
  randomize;
  for i := 1 to 5 do
    begin
      Random1 := Player1.Pick;
      writeln(Player1.GetName,' draws number ', Random1);
      Random2 := Player2.Pick;
      writeln(Player2.GetName,' draws number ', Random2);
      writeln;
      if Random1 > Random2 then
        Player1.AddPoints(1);
      if Random2 > Random1 then
        Player2.AddPoints(1);
    end;
    Player1.ShowPoints;
    Player2.ShowPoints;
    writeln;
    if Player1.GetPoints > Player2.GetPoints then
      writeln (Player1.GetName, ' wins.')
    else
      begin
        if Player2.GetPoints > Player1.GetPoints then
          writeln (Player2.GetName, ' wins.')
        else
          writeln('Draw');
      end;
  Player1.Free;
  Player2.Free;
  readln;
end.
    

Input and output

Please enter the forename of the first player. JUSTIN
Please enter the forename of the second player. JORDAN
Hi! My name is Jordan. I feel lucky.
Justin draws number 1
Jordan draws number 2

Justin draws number 3
Jordan draws number 1

Justin draws number 1
Jordan draws number 3

Justin draws number 1
Jordan draws number 3

Justin draws number 1
Jordan draws number 2

Points for Justin: 1
Points for Jordan: 4

Jordan wins.

Inheritance Example using Graphics

You should find this section easier if you are familiar with the material in the Vector Graphics section of our Graphics tutorial. We write a TShape class for a basic shape with the integer fields LineColour and FillColour and the Boolean fields ShapeFilled and ThickLine. All of the derived classes will need these fields and the methods to write (set) and read (get) them. The TRectangle and TCircle classes are derived from TShape, and TCrossRectangle is derived from TRectangle. TCrossRectangle inherits from both TRectangle and TShape.

Program InheritanceDemo as it stands runs in Lazarus. If the shapes are incomplete when you run the program, minimise then maximise the graphics window. To run it in Delphi, you need to download and include wingraph.pas, as detailed in Using WinGraph in Delphi in the Graphics tutorial. The first four lines should be:
program InheritanceDemo;
  {$APPTYPE CONSOLE}
uses
  SysUtils, Shapes in 'Shapes.pas', WinGraph in 'wingraph.pas';   

You also need to change Graph to WinGraph in the uses section of Shapes.pas. We show the output below.

Output from program InheritanceDemo

Output from program InheritanceDemo

program InheritanceDemo;
uses
  SysUtils, Graph, Shapes in 'Shapes.pas';
var
  Gd, Gm : smallint;
  Circle : TCircle;
  Rect : TRectangle;
  CrossRect : TCrossRectangle;

begin
  //If the shapes are incomplete, minimise then maximise the graphics window.
  Gd := Detect;
  Gm := 0;
  InitGraph(Gd, Gm, '');
  //Create white background
  Rect:= TRectangle.Create;
  Rect.SetLineColour(white);
  Rect.SetFillcolour(white);
  Rect.SetFill(True);
  Rect.Draw(0, 0, getMaxX, getMaxY);
  //Blue circle
  Circle:= TCircle.Create;
  Circle.setLineColour(blue);
  Circle.Draw(100, 100, 100);
  //Yellow rectangle
  Rect.SetFillcolour(yellow);
  Rect.Draw(300, 400, 500, 600);
  //Light red filled circle
  Circle.SetFillcolour(lightred);
  Circle.SetFill(True);
  Circle.Draw(200, 200, 100);
  //Light blue rectangle
  Rect.SetFill(True);
  Rect.SetFillcolour(lightblue);
  Rect.Draw(30, 40, 170, 150);
  //Green rectangle with cross
  CrossRect := TCrossRectangle.Create;
  CrossRect.SetLineWidth(True);
  CrossRect.SetLineColour(green);
  CrossRect.SetFill(False);
  CrossRect.Draw(200, 300, 400, 500);
  
  Circle.Free;
  Rect.Free;
  CrossRect.Free;
  readln;
end.           

unit Shapes;

interface

type
  TShape = class(TObject)
  protected
    LineColour, FillColour : integer;
    ShapeFilled, ThickLine: Boolean;
  public
    procedure SetLineWidth(Thick: Boolean);
    procedure SetLineColour(Colour : integer);
    procedure SetFillColour(Colour : integer);
    procedure SetFill(Filled : Boolean);
    function GetLineColour: integer;
  end;

  TCircle = class(TShape)
  public
    procedure Draw(x, y, CircleRadius: integer);
  end;

  TRectangle = class(TShape)
  public
    procedure Draw(x1, y1, x2, y2 : integer);
  end;

  TCrossRectangle = class(TRectangle)
  public
    procedure Draw(x1, y1, x2, y2 : integer);
  end;

implementation
uses
  Graph; //WinGraph in the Delphi version.

procedure  TShape.SetLineWidth(Thick: Boolean);
begin
 if Thick then
   SetLineStyle(Solidln, 0, ThickWidth)
 else
   SetLineStyle(Solidln, 0, NormWidth)
end;

procedure TShape.SetLineColour(Colour : integer);
begin
   LineColour := Colour;
end;

procedure TShape.SetFillcolour(Colour : integer);
begin
  FillColour := Colour;
end;

function TShape.GetLineColour: integer;
begin
  result := LineColour;
end;

procedure TShape.SetFill(Filled : Boolean);
begin
  ShapeFilled := Filled;
end;

procedure TCircle.Draw(x, y, CircleRadius: integer);
begin
  setColor(LineColour);
  if ShapeFilled then
    begin
      setFillStyle(SolidFill, FillColour);
      fillEllipse(x, y, CircleRadius, CircleRadius);
    end
  else
    Circle(x, y, CircleRadius);
end;

procedure TRectangle.Draw(x1, y1, x2, y2 : integer);
begin
  setColor(LineColour);
  if ShapeFilled then
    begin
      setFillStyle(SolidFill, FillColour);
      bar(x1, y1, x2, y2);
    end
  else
    Rectangle(x1, y1, x2, y2);
end;

procedure TCrossRectangle.Draw(x1, y1, x2, y2 : integer);
begin
  setColor(LineColour);
  moveTo(x1,y1);
  lineTo(x2,y2);
  moveTo(x1,y2);
  lineTo(x2,y1);
  //Call the draw procedure in the base class.
  inherited draw(x1, y1, x2, y2);
end;

end.  

Experimenting with Inheritance

  1. Write a class based on TRectangle to draw a rectangle split into 4 equal rectangles by a vertical line and a horizontal line. Write a program to use objects of your class.
  2. Write classes to draw flags. We suggest that you start with a relatively simple example such as the flag of Poland, Sweden or Japan. Write one program that uses objects of each of your classes.
  3. Experiment with methods that flip and rotate your shapes.
  4. Experiment with 3D shapes, starting with a rectangle.
Programming - a skill for life!

Classes (including the inbuilt TQueue and TStringList), objects, inheritance and properties