目录
一、类声明(Class Declarations)
二、方法解决说明(Method Resolution Clause)
三、更改继承实现(Changing Inherited Implementations)
四、通过委托实现接口(Implementing Interfaces by Delegation)
五、委托接口类型属性(Delegating to an Interface-Type Property)
六、委托给类类型属性(Delegating to a Class-Type Property)
接口一经声明,必须在类中实现后才能使用。在类的声明中,在类的祖先名称之后指定了类所实现的接口。
此类声明的形式如下 :
type className = class (ancestorClass, interface1, ..., interfaceN)
memberList
end;
例如:
type
TMemoryManager = class(TInterfacedObject, IMalloc, IErrorInfo)
// ...
声明了一个名为 TMemoryManager 的类,该类实现了 IMalloc 和 IErrorInfo 接口。当一个类实现一个接口时,它必须实现(或继承实现)接口中声明的每个方法。
以下是 System.TInterfacedObject 的声明(在 Windows 平台上,在其他平台上,声明略有不同):
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 实现了 IInterface 接口。因此,TInterfacedObject 声明并实现了三个 IInterface 方法中的每一个。
实现接口的类也可用作基类。(上面的第一个示例将 TMemoryManager 声明为 TInterfacedObject 的直接继承)。每个接口都继承自 IInterface,实现接口的类必须实现 QueryInterface、_AddRef 和 _Release 方法。单元 System 中的 TInterfacedObject 实现了这些方法,因此是一个方便的基类,可以从中派生出其他实现接口的类。
实现接口时,接口的每个方法都会被映射到实现类中的一个方法上,该方法具有相同的结果类型、相同的调用约定、相同的参数数以及每个位置上相同类型的参数。默认情况下,每个接口方法都会映射到实现类中的同名方法。
通过在类声明中包含方法解析子句,可以覆盖默认的基于名称的映射。当一个类实现了两个或多个具有相同命名方法的接口时,可以使用方法解析子句来解决命名冲突。
方法解析子句的形式如下 :
procedure interface.interfaceMethod = implementingMethod;
或者
function interface.interfaceMethod = implementingMethod;
其中,implementingMethod 是该类或其祖先类中声明的方法。implementingMethod 可以是类声明中稍后声明的方法,但不能是其他模块中声明的祖先类的私有方法。
例如 :
type
TMemoryManager = class(TInterfacedObject, IMalloc, IErrorInfo)
function IMalloc.Alloc = Allocate;
procedure IMalloc.Free = Deallocate;
// ...
end;
将 IMalloc 的 Alloc 和 Free 方法映射到 TMemoryManager 的 Allocate 和 Deallocate 方法上。
方法解析子句不能改变父类引入的映射。
子类可以通过覆盖实现方法来改变特定接口方法的实现方式。这要求实现方法是虚拟的或动态的。
类还可以重新实现从祖先类继承的整个接口。这需要在子类的声明中重新列出接口。例如:
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;
重新实现接口会隐藏同一接口的继承实现。因此,父类中的方法解析条款对重新实现的接口没有任何影响。
implements 指令允许将接口的实现委托给实现类中的一个属性。例如 :
property MyInterface: IMyInterface read FMyInterface implements IMyInterface;
声明了一个名为 MyInterface 的属性,该属性实现了接口 IMyInterface。
implements 指令必须是属性声明中的最后一个指定符,并且可以列出多个接口,中间用逗号隔开。委托属性 :
用于实现委托接口的类应该派生自 System.TAggregatedObject。
如果委托属性属于接口类型,则该接口或其派生接口必须出现在声明该属性的类的祖先列表中。委托属性必须返回一个对象,该对象的类完全实现了 implements 指令指定的接口,并且不含方法解析子句。例如 :
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;
如果委托属性属于一个类的类型,则在搜索外层类及其祖先之前,先搜索该类及其祖先中实现指定接口的方法。因此,可以在属性指定的类中实现某些方法,而在声明属性的类中实现其他方法。方法解析子句可以按通常的方式用于解决歧义或指定特定方法。一个接口不能由多个类类型属性实现。例如 :
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;