Object Pascal provides full support for advanced Object-Oriented Programming concepts, allowing for flexible and maintainable code through hierarchical design.
1. Inheritance (class(ParentClass))
Inheritance is the mechanism where a new class (the descendant or child) derives characteristics and behavior (fields and methods) from an existing class (the ancestor or parent).
- Syntax: A class inherits by including the parent class name in parentheses after the
classkeyword. - Benefit: Code reuse. Descendant classes automatically have all public, protected, and published members of the ancestor.
- Root: In Delphi, all classes ultimately descend from
TObject.
// TPerson is the ancestor class
type
TPerson = class(TObject)
protected
fName: String;
procedure SetName(const Name: String);
public
constructor Create(const Name: String);
end;
// TEmployee is the descendant class (inherits from TPerson)
type
TEmployee = class(TPerson)
private
fEmployeeID: Integer;
public
// TEmployee automatically has fName, SetName, and Create
procedure AssignID(ID: Integer);
function GetFullName: String;
end;
2. Polymorphism (Many Forms)
Polymorphism is the ability of different objects to respond to the same method call in a way that is specific to their own class. This is achieved through method overriding using the virtual and override keywords.
A. Virtual Methods
A method in the ancestor class must be declared as virtual to signal that it can be overridden by descendant classes.
B. Overriding Methods
In the descendant class, the method signature must be identical to the ancestor’s virtual method and be marked with the override keyword.
// Ancestor Class
type
TShape = class(TObject)
public
// 1. Must be declared as virtual to allow overriding
function CalculateArea: Double; virtual;
end;
// Descendant Class 1
type
TRectangle = class(TShape)
public
// 2. Must be declared as override
function CalculateArea: Double; override;
end;
// Implementation
function TShape.CalculateArea: Double;
begin
Result := 0; // Default implementation
end;
function TRectangle.CalculateArea: Double;
begin
// Implementation specific to TRectangle
Result := fWidth * fHeight;
end;
3. Calling the Ancestor (inherited)
Inside an overridden method (especially constructors or event handlers), you often need to execute the code from the parent class first. You do this using the inherited keyword.
constructor TEmployee.Create(const Name: String);
begin
// Call the TPerson's constructor first to initialize fName
inherited Create(Name);
// Now initialize TEmployee's fields
fEmployeeID := 0;
end;
procedure TEmployee.SetName(const Name: String);
begin
// Call the ancestor's SetName procedure
inherited SetName(Name);
// Add specific TEmployee logic (e.g., logging the change)
Log.Add('Employee name changed');
end;
4. Abstract Classes and Methods
An Abstract Class is a class that cannot be instantiated directly because it has one or more methods that are declared but not implemented.
- Abstract Method: A method marked with the
abstractdirective (which also impliesvirtual). It acts as a contract, forcing all non-abstract descendant classes to provide anoverrideimplementation.
// TDataSourceReader is an abstract class
type
TDataSourceReader = class(TObject)
public
// This class cannot be instantiated, as its purpose is to define an interface
function ReadData: TStringList; virtual; abstract;
end;
// TFileCsvReader is a concrete class
type
TFileCsvReader = class(TDataSourceReader)
public
// Must implement (override) the abstract method
function ReadData: TStringList; override;
end;
5. Type Checking (is and as)
When working with polymorphism, you often need to check the actual type of an object reference or cast it to a specific type to access specific features.
isOperator (Type Check): Returns a boolean (TrueorFalse) indicating whether an object is compatible with a given class (or any of its descendants).asOperator (Type Cast): Attempts to convert an object reference to a specific type. If the conversion is impossible, it raises an exception. Use this only after usingisor if the type is guaranteed.
procedure ProcessShape(SomeShape: TShape);
begin
// 1. Check the type first
if SomeShape is TRectangle then
begin
// 2. Cast safely to access the specific methods/properties of TRectangle
var Rect: TRectangle;
Rect := SomeShape as TRectangle;
// Access TRectangle-specific field
Rect.Width := 10;
end;
end;
