考虑此接口及其实现。
unit utest;
interface
{$MODE OBJFPC}
type
IIntfA = interface
procedure writeA();
end;
IIntfB = interface(IIntfA)
procedure writeB();
end;
TADelegateClass = class(TInterfacedObject, IIntfA)
public
procedure writeA();
end;
TAClass = class(TInterfacedObject, IIntfA)
private
delegateA : IIntfA;
public
constructor create(const AInst : IIntfA);
destructor destroy(); override;
property A : IIntfA read delegateA implements IIntfA;
end;
TBClass = class(TAClass, IIntfB)
public
procedure writeB();
end;
implementation
procedure TADelegateClass.writeA();
begin
writeln('Implement IIntfA through delegation');
end;
constructor TAClass.create(const AInst : IIntfA);
begin
delegateA := AInst;
end;
destructor TAClass.destroy();
begin
inherited destroy();
delegateA := nil;
end;
procedure TBClass.writeB();
begin
writeln('Implement IIntfB');
end;
end.
以下程序将无法编译。
program test;
{$MODE OBJFPC}
uses
utest;
var b : IIntfB;
begin
b := TBClass.create(TADelegateClass.create());
b.writeA();
b.writeB();
end.
免费Pascal(版本3.0.4)抱怨
Error: No matching implementation for interface method "writeA;" found
。
在声明TBClass
的行中。
当然,我可以通过在writeA
或TAClass
中实现TBClass
并从那里调用writeA
的{{1}}方法来成功地编译它。
TADelegateClass
是通过接口委托实现的TAClass
接口的具体实现,但是为什么IIntfA
的后代TBClass
却不被认为是{{1}的具体实现}界面?
答案 0 :(得分:2)
TAClass
是IIntfA
接口通过以下方式的具体实现 接口委派,但为什么TBClass
是TAClass
的后代, 不被认为是IIntfA
接口的具体实现?
简短的回答:不是IIntfA
才是问题,不是IIntfB
才是问题。
长答案:接口继承是C ++ vtable继承,有时不直观。
在示例中:
IIntfB = interface(IIntfA)
procedure writeB();
end;
实际上可以写为
IIntfB = interface
procedure writeA();
procedure writeB();
end;
实现多个接口时,公共部分不会重复使用。编译器通过实现方法来设置各个表,例如:
TADelegateClass:
QueryInterface(IIntfA) = Self.vtable_IIntfA
vtable_IIntfA.writeA <- Self.writeA
TAClass:
QueryInterface(IIntfA) = delegateA.vtable_IIntfA
TBClass:
QueryInterface(IIntfA) = inherited delegateA.vtable_IIntfA
QueryInterface(IIntfB) = vtable_IIntfB
vtable_IIntfB.writeA <- (this is missing!)
vtable_IIntfB.writeB <- Self.writeB
TBClass确实没有实现IIntfB.writeA
。
可以通过手动将方法分配给特定接口并观察错误消失来验证这一点:
TBClass = class(TAClass, IIntfB)
public
procedure IIntfB.writeA = writeB;
// dummy method, shows IIntfB.writeA is missing
可悲的是,我不知道有什么方法可以告诉编译器从另一个接口访问映射。 FWIW,Delphi具有相同的错误/缺点。