Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 7: Object-Oriented Programming in Pascal

Object-oriented programming (OOP) is a paradigm in which applications and programs are designed around “objects”. It helps you organize data and keep code modular. Pascal implements OOP with classes and objects, and this chapter introduces the basic concepts: classes, objects, inheritance, polymorphism, and encapsulation.

Free Pascal’s default mode doesn’t accept the class keyword. To use the examples in this chapter, put {$mode objfpc}{$H+} on the first line of the program file, before program, or compile with fpc -Mobjfpc. The {$H+} part makes string mean a long string with no 255-character limit.

{$mode objfpc}{$H+}
program ClassesExample;

Classes and objects

Defining a class

A class is a blueprint for creating objects. It defines the properties (fields) and methods (procedures and functions) that every object created from it can use.

type
  TPerson = class
    private
      FName: string;
      FAge: integer;
    public
      constructor Create(name: string; age: integer);
      procedure Display;
  end;

Implementing the class methods

constructor TPerson.Create(name: string; age: integer);
begin
  FName := name;
  FAge := age;
end;

procedure TPerson.Display;
begin
  writeln('Name: ', FName);
  writeln('Age: ', FAge);
end;

Creating objects

var
  person: TPerson;

begin
  person := TPerson.Create('Alice', 30);
  person.Display;
  person.Free;
end.

Inheritance

Inheritance lets one class take on the properties and methods of another. You can reuse code this way and arrange classes in a hierarchy.

Defining a base class and a derived class

type
  TPerson = class
    private
      FName: string;
      FAge: integer;
    public
      constructor Create(name: string; age: integer);
      procedure Display; virtual;
  end;

  TEmployee = class(TPerson)
    private
      FSalary: real;
    public
      constructor Create(name: string; age: integer; salary: real);
      procedure Display; override;
  end;

Implementing the methods

constructor TPerson.Create(name: string; age: integer);
begin
  FName := name;
  FAge := age;
end;

procedure TPerson.Display;
begin
  writeln('Name: ', FName);
  writeln('Age: ', FAge);
end;

constructor TEmployee.Create(name: string; age: integer; salary: real);
begin
  inherited Create(name, age);
  FSalary := salary;
end;

procedure TEmployee.Display;
begin
  inherited Display;
  writeln('Salary: ', FSalary:0:2);
end;

Creating objects of derived class

var
  employee: TEmployee;

begin
  employee := TEmployee.Create('Bob', 25, 55000.0);
  employee.Display;
  employee.Free;
end.

Polymorphism

With polymorphism, the method that runs depends on the actual type of the object, even when you call it through a reference of the base class type. Virtual methods and method overriding make this work.

Example of polymorphism

var
  person, someone: TPerson;
  employee: TEmployee;

begin
  person := TPerson.Create('Charlie', 40);
  employee := TEmployee.Create('Dave', 28, 62000.0);

  person.Display;     { Calls TPerson's Display }
  employee.Display;   { Calls TEmployee's Display }

  someone := employee; { Assigning derived class object to base class reference }
  someone.Display;     { Calls TEmployee's Display due to polymorphism }

  person.Free;
  employee.Free;       { Also frees the object that someone refers to }
end.

someone and employee refer to the same object, so it’s freed only once. Assigning employee to person instead would lose the only reference to Charlie’s object, which could then never be freed, and person.Free followed by employee.Free would free Dave’s object twice.

Encapsulation

Encapsulation means hiding an object’s internal state so that all interaction has to go through its methods. This keeps code modular and protects the object’s integrity.

Example of encapsulation

type
  TBankAccount = class
    private
      FBalance: real;
    public
      constructor Create(initialBalance: real);
      procedure Deposit(amount: real);
      procedure Withdraw(amount: real);
      procedure DisplayBalance;
  end;

constructor TBankAccount.Create(initialBalance: real);
begin
  FBalance := initialBalance;
end;

procedure TBankAccount.Deposit(amount: real);
begin
  if amount > 0 then
    FBalance := FBalance + amount;
end;

procedure TBankAccount.Withdraw(amount: real);
begin
  if (amount > 0) and (amount <= FBalance) then
    FBalance := FBalance - amount;
end;

procedure TBankAccount.DisplayBalance;
begin
  writeln('Balance: ', FBalance:0:2);
end;

Using the encapsulated class

var
  account: TBankAccount;

begin
  account := TBankAccount.Create(1000.0);
  account.Deposit(500.0);
  account.Withdraw(200.0);
  account.DisplayBalance;  { Output: Balance: 1300.00 }
  account.Free;
end.