Composition Over Inheritance
Made Native

You know interfaces, and you know inheritance. Delphi's implements keyword bridges the gap, allowing a class to delegate the implementation of an interface to an internal property.

This enables Multiple Inheritance of Implementation (conceptually) without the "Diamond Problem" complexity, by aggregating separate implementation objects into a single host.

Architectural Insight

Instead of writing wrapper methods that simply call FInnerObj.Method, the compiler automatically routes QueryInterface calls for the specified interface to the property instance.

Architecture Trade-offs

Comparison: Standard Inheritance vs. Delegation (Implements)


The implements Directive

In standard Delphi interface implementation, the host class must implement every method defined in the interface. The implements directive modifies this behavior by telling the compiler: "Do not look for the methods of this interface in my method table. Instead, delegate the implementation to this property."

When QueryInterface is called on the host for the specific interface ID (IID), the host returns the pointer to the object or interface held in the specified property. This allows you to mix in behaviors from other classes dynamically.


Syntax Anatomy

Click the interactive code tokens below to understand how the compiler wires the Virtual Method Table (VMT).

Unit: UHostController.pas Delphi RTL
type
// The Interface Definition
ILogger = interface
  ['{...}']
  procedure Log(Msg: string);
end;

// The Host Class
THost = class(TInterfacedObject, ILogger)
private
  FLoggerImpl: TMyLogger;
public
  constructor Create;
  property Logger: ILogger
    read FLoggerImpl
    implements ILogger;
end;
Select a Token
Click on parts of the code to see how Delphi handles the delegation logic internally.

Architectural Patterns

Three powerful ways to leverage `implements` in production code.

Simulating Multiple Inheritance
Delphi classes only support single inheritance. However, using `implements`, a single class can expose interfaces implemented by entirely different internal objects.
THost Class
Core Host Logic
Delegate 1
IPersist
Handles Saving
Delegate 2
IValidate
Handles Rules

                
!

The Reference Counting Trap

The biggest danger when using `implements` is the Circular Reference. If your Host holds a reference to the Delegate (Implementation), and the Delegate holds a reference back to the Host (which often happens implicitly in interfaces), you get a memory leak.

The Solution: TAggregatedObject

Standard TInterfacedObject maintains its own RefCount. TAggregatedObject delegates its RefCounting to a "Controller" (the Host).

  • Host is the Controller.
  • Delegate inherits from TAggregatedObject.
  • Pass Self (Host) to Delegate's constructor.
Correct Implementation
type
// Delegate Class
TMyDelegate = class(TAggregatedObject, IMyIntf)
...
end;

// Host Class
THost = class(TInterfacedObject, IMyIntf)
private
FImpl: TMyDelegate;
public
constructor Create;
property AsIntf: IMyIntf
  read FImpl implements IMyIntf;
end;

// Construction
constructor THost.Create;
begin
// Pass Host (Self) as Controller
FImpl := TMyDelegate.Create(Self);
end;