通过接口委托实现不传递给后代
Implementation through interface delegation not pass to descendant
考虑这个接口及其实现。
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.
Free Pascal(版本 3.0.4)抱怨
Error: No matching implementation for interface method "writeA;" found
。
在声明 TBClass
的行。
当然,我可以通过在 TAClass
或 TBClass
中实现 writeA
并从那里调用 TADelegateClass
的 writeA
方法来成功编译它。
TAClass
是 IIntfA
接口通过接口委托的具体实现,但是为什么 TAClass
的后代 TBClass
不被认为是 [=] 的具体实现20=] 界面?
TAClass
is concrete implementation of IIntfA
interface through
interface delegation but why TBClass
, which is descendant of TAClass
,
is not considered a concrete implementation of IIntfA
interface?
简答:问题不在于 IIntfA
,而是 IIntfB
不完整。
长答:接口继承是C++虚表继承,有时不直观。
示例中:
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 具有相同的 bug/shortcoming。
考虑这个接口及其实现。
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.
Free Pascal(版本 3.0.4)抱怨
Error: No matching implementation for interface method "writeA;" found
。
在声明 TBClass
的行。
当然,我可以通过在 TAClass
或 TBClass
中实现 writeA
并从那里调用 TADelegateClass
的 writeA
方法来成功编译它。
TAClass
是 IIntfA
接口通过接口委托的具体实现,但是为什么 TAClass
的后代 TBClass
不被认为是 [=] 的具体实现20=] 界面?
TAClass
is concrete implementation ofIIntfA
interface through interface delegation but whyTBClass
, which is descendant ofTAClass
, is not considered a concrete implementation ofIIntfA
interface?
简答:问题不在于 IIntfA
,而是 IIntfB
不完整。
长答:接口继承是C++虚表继承,有时不直观。
示例中:
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 具有相同的 bug/shortcoming。