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.