Interface implementation in Delphi: Implementing Interfaces

 

        

Table of contents

1. Class Declarations

2. Method Resolution Clause

3. Changing Inherited Implementations

4. Implementing Interfaces by Delegation

5. Delegating to an Interface-Type Property

6. Delegating to a Class-Type Property


        Once an interface is declared, it must be implemented in a class before it can be used. In the class declaration, the interfaces implemented by the class are specified after the name of the class's ancestors.

1. Class Declarations

Such declarations take the following form:

type className = class (ancestorClass, interface1, ..., interfaceN)
   memberList
end;

For example:

type
  TMemoryManager = class(TInterfacedObject, IMalloc, IErrorInfo)
    // ...

        Declare a class called TMemoryManager that implements the IMalloc and IErrorInfo interfaces. When a class implements an interface, it must implement (or inherit from implementing) every method declared in the interface.

Here is the declaration of System.TInterfacedObject (on the Windows platform, on other platforms the declaration is slightly different):

type
 TInterfacedObject = class(TObject, IInterface)
 protected
   FRefCount: Integer;
   function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
   function _AddRef: Integer; stdcall;
   function _Release: Integer; stdcall;
 public
   procedure AfterConstruction; override;
   procedure BeforeDestruction; override;
   class function NewInstance: TObject; override;
   property RefCount: Integer read FRefCount;
 end;

TInterfacedObject implements the IInterface interface. Therefore, TInterfacedObject declares and implements each of the three IInterface methods.

A class implementing an interface can also be used as a base class. (The first example above declares TMemoryManager as a direct inheritance of TInterfacedObject). Each interface inherits from IInterface, and the class that implements the interface must implement the QueryInterface, _AddRef, and _Release methods. TInterfacedObject in unit System implements these methods and is therefore a convenient base class from which other classes implementing the interface can be derived.

When an interface is implemented, each method of the interface is mapped to a method in the implementing class that has the same result type, the same calling convention, the same number of parameters, and the same type of parameters at each position. By default, each interface method maps to a method of the same name in the implementing class.
 

2. Method Resolution Clause

The default name-based mapping can be overridden by including a method resolution clause in the class declaration. When a class implements two or more interfaces with identically named methods, the method resolution clause can be used to resolve naming conflicts.

The method resolution clause has the following form:

procedure interface.interfaceMethod = implementingMethod;

or

function interface.interfaceMethod = implementingMethod;

where implementingMethod is a method declared in this class or an ancestor class. implementingMethod can be a method declared later in the class declaration, but cannot be a private method of an ancestor class declared in another module.

For example:

type
  TMemoryManager = class(TInterfacedObject, IMalloc, IErrorInfo)
    function IMalloc.Alloc = Allocate;
    procedure IMalloc.Free = Deallocate;
   // ...
  end;

Map the Alloc and Free methods of IMalloc to the Allocate and Deallocate methods of TMemoryManager.

Method resolution clauses cannot change mappings introduced by parent classes.

3. Changing Inherited Implementations

Subclasses can change how a particular interface method is implemented by overriding the implementing method. This requires the implementing method to be virtual or dynamic.

Classes can also reimplement entire interfaces inherited from ancestor classes. This requires relisting the interface in the declaration of the subclass. For example:

 

type
  IWindow = interface
    ['{00000115-0000-0000-C000-000000000146}']
    procedure Draw;
    // ...
  end;
  TWindow = class(TInterfacedObject, IWindow)
    // TWindow implements IWindow pocedure Draw;
    // ...
  end;
  TFrameWindow = class(TWindow, IWindow)
    // TFrameWindow reimplements IWindow procedure Draw;
    // ...
  end;

        Reimplementing an interface hides inherited implementations of the same interface. Therefore, method resolution clauses in parent classes have no effect on reimplemented interfaces.

4. Implementing Interfaces by Delegation

The implements directive allows to delegate the implementation of an interface to a property in the implementing class. For example:

property MyInterface: IMyInterface read FMyInterface implements IMyInterface;

A property named MyInterface is declared that implements the interface IMyInterface.

The implements directive must be the last specifier in the attribute declaration, and can list multiple interfaces, separated by commas. Delegate property:

  • Must be a class or interface type.
  • Cannot be an array property and cannot have an index specifier.
  • Must have read specifier. If the property uses a read method, that method must use the default register calling convention, cannot be dynamic (although it can be virtual), and cannot specify a message instruction.

The class used to implement the delegate interface should be derived from System.TAggregatedObject.

5. Delegating to an Interface-Type Property

If a delegated property is of an interface type, that interface or a derived interface must appear in the list of ancestors of the class declaring the property. A delegated property must return an object whose class fully implements the interface specified by the implements directive and does not contain a method resolution clause. For example:

type
  IMyInterface = interface
    procedure P1;
    procedure P2;
  end;
  TMyClass = class(TObject, IMyInterface)
    FMyInterface: IMyInterface;
    property MyInterface: IMyInterface read FMyInterface implements IMyInterface;
  end;
var
  MyClass: TMyClass;
  MyInterface: IMyInterface;
begin
  MyClass := TMyClass.Create;
  MyClass.FMyInterface := ...// some object whose class implements IMyInterface
  MyInterface := MyClass;
  MyInterface.P1;
end;

6. Delegating to a Class-Type Property

If the delegated property is of the type of a class, the class and its ancestors are searched for methods that implement the specified interface before searching the outer class and its ancestors. Therefore, some methods can be implemented in the class specified by the attribute and other methods in the class declaring the attribute. Method resolution clauses can be used in the usual way to resolve ambiguities or to specify specific methods. An interface cannot be implemented by more than one class type property. For example:

type
  IMyInterface = interface
    procedure P1;
    procedure P2;
  end;
  TMyImplClass = class
    procedure P1;
    procedure P2;
  end;
  TMyClass = class(TInterfacedObject, IMyInterface)
    FMyImplClass: TMyImplClass;
    property MyImplClass: TMyImplClass read FMyImplClass implements IMyInterface;
    procedure IMyInterface.P1 = MyP1;
    procedure MyP1;
  end;
procedure TMyImplClass.P1;
     // ...
procedure TMyImplClass.P2;
     // ...
procedure TMyClass.MyP1;
     // ...
var
  MyClass: TMyClass;
  MyInterface: IMyInterface;
begin
  MyClass := TMyClass.Create;
  MyClass.FMyImplClass := TMyImplClass.Create;
  MyInterface := MyClass;
  MyInterface.P1;  // calls TMyClass.MyP1;
  MyInterface.P2;  // calls TImplClass.P2;
end;

Guess you like

Origin blog.csdn.net/sensor_WU/article/details/132492759