这不能编译的原因是什么?
type
IInterfaceA = interface ['{44F93616-0161-4912-9D63-3E8AA140CA0D}']
procedure DoA;
end;
IInterfaceB = interface(IInterfaceA) ['{80CB6D35-E12F-462A-AAA9-E7C0F6FE0982}']
procedure DoB;
end;
TImplementsAB = class(TSingletonImplementation, IInterfaceB)
procedure DoA;
procedure DoB;
end;
var
ImplementsAB: TImplementsAB;
InterfaceA: IInterfaceA;
InterfaceB: IInterfaceB;
begin
ImplementsAB := TImplementsAB.Create;
InterfaceA := ImplementsAB; >> incompatible types
...
end
相比之下,这就是我的工作方式:
InterfaceA := ImplementsAB as InterfaceB;
或
InterfaceA := InterfaceB;
我的意思是,如果IInterfaceB继承自IInterfaceA且TImplementsAB实现了IInterfaceB,那么实现IInterfaceA并且类型兼容也不合逻辑吗?
答案 0 :(得分:28)
这是因为早期的OLE / COM有一个错误,Borland决定与它兼容。本文提到了这一点:New Delphi language feature: Multiple inheritance for interfaces in Delphi for .NET。解决方案是像Mikael所写的那样在类中明确列出所有祖先接口。
链接文章的一些引用:
问题出在COM本身。要加载模块,COM将加载DLL,GetProcAddress在一个众所周知的入口点上,该入口点应该从DLL导出,调用DLL函数获取IUnknown接口,然后调用IClassFactory的QueryInterface。问题是,当Microsoft添加对IClassFactory2的支持时,他们在查询IClassFactory的现有代码之后添加了IClassFactory2的QueryInterface。只有在IClassFactory的查询失败时才会请求IClassFactory2。
因此,COM永远不会在任何实现IClassFactory2和IClassFactory的COM服务器上请求IClassFactory2。
这个错误很长一段时间都存在于COM中。微软表示,他们无法使用操作系统服务包修复COM加载程序,因为Word和Excel(当时)都依赖于错误的行为。无论是否在最新版本的COM中修复了它,Borland必须提供一些方法来保护Win32 Delphi中的这种行为以应对可预见的未来。突然将所有祖先添加到以前不存在的实现类中很可能会破坏现有的代码,这些代码无意中与COM加载器处于相同的模式中。
答案 1 :(得分:6)
使其工作的另一种方法是在类声明中包含两个接口。
TImplementsAB = class(TSingletonImplementation, IInterfaceA, IInterfaceB)
procedure DoA;
procedure DoB;
end;
我想这是编译器认识到TImplementsAB
同时实现IInterfaceA
和IInterfaceB
所需要的。