Delphi允许使用implements关键字进行接口委派.
例如
IIndep1 = interface
function foo2: integer;
end;
IIndep2 = interface
function goo2: integer;
end;
TIndep1And2 = class(TInterfacedObject, IIndep1, IIndep2)
private
FNested : IIndep1; //e.g. passed via constructor or internally created (not shown here)
public
Constructor Create(AIndep1: IIndep1);
function goo2: integer;
property AsIndep1 : IIndep1 read FNested implements IIndep1;
end;
这很好,但不适用于继承的接口. (错误消息“缺少接口方法ILev1.foo的实现”)
ILev1 = interface
function foo: Integer;
end;
ILev2 = interface(ILev1)
function goo: Integer;
end;
TLev2Fails = class(TInterfacedObject, ILev1, ILev2) //Also fails with ILev2 alone (Error: "ILev1 not mentioned in interface list")
private
FNested : ILev1; //passed via constructor or internally created
public
Constructor Create(AILev1: ILev1);
function goo: Integer;
property AsLev1 : ILev1 read FNested implements ILev1;
end;
解决方法是添加一个额外的祖先类
TLev1Wrapper = class(TInterfacedObject, ILev1)
private
FNested : ILev1; //passed via constructor or internally created
public
Constructor Create(AILev1: ILev1);
property AsLev1 : ILev1 read FNested implements ILev1;
end;
TLev2Works = class(TLev1Wrapper, ILev2)
public
function goo: Integer;
end;
有没有办法避免包装类祖先?
[编辑]
只是关于接口委派的说明,使用工具的目的是避免直接满足接口,而是将该需求传递给聚合或组合成员.提供完整的界面并手动委派给组合成员会失败使用工具来指导界面所带来的好处.实际上,在这种情况下,implements关键字和属性可能会被删除.
最佳答案 这看起来像编译器试图强制执行
the expectations (read: requirements) of IUnknown.QueryInterface:
For any one object, a specific query for the IUnknown interface on any
of the object’s interfaces must always return the same pointer value.
如果您能够在自己实现派生接口的同时委派基接口的实现,那么:
obj := TLev2Fails.Create(otherLev1); // Assuming your class could compile
lev1 := obj as ILev1; // yields reference to otherLev1 implementor
lev2 := obj as ILev2; // yields reference to TLev2Fails instance
unk1 := lev1 as IUnknown; // returns IUnknown of otherLev1 implementor
unk2 := lev2 as IUnknown; // returns IUnknown of obj TLev2fails instance
如果您的嵌套对象被正确实现为TAggregatedObject派生类,则不会出现这种情况,但是编译器无法知道是否是这种情况,更不用说强制执行它了,相反它似乎只需要实现派生接口那么你还必须直接实现接口本身继承的任何接口.
在这种情况下编译器错误不是很有用,虽然它可以被解读为告诉你你需要做什么,而不是为什么你需要在这种情况下这样做,这对于编译器错误并不常见.
如果您希望在这种情况下委派,那么您必须“手动委派”.
虽然这会失去工具设施的好处,但它至少保留了重复使用的好处,但不太方便.
注意:即使您的委托实现基于TAggregatedObject,编译器仍然无法确定这些实现细节是否满足QueryInterface的要求,因此您仍然会收到此错误(即使使用委派接口的类引用).
您仍然必须手动委派.
说了这么多,我现在无法看到当接口没有继承关系的情况下这有什么不同,但很有可能这是有效的,我只是没有完成所有必要的’思想实验’向自己证明. 🙂
可能是编译器在它认为可以/应该是的情况下只是格外谨慎,并且文档根本没有提到这导致的实现限制.
或者它可能是编译器中的一个错误,尽管我认为行为有足够明显的原因,并且行为本身如此完善和一致(在Delphi 7中重现了完全相同的行为),相关文档中的遗漏是更可能的解释.