当一个类实现了后代接口时,为什么它不自动算作实现了基接口?

发布于 2024-12-20 20:00:49 字数 833 浏览 2 评论 0原文

这无法编译的原因是什么?

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 并保持类型兼容是不合逻辑的吗?

What's the reason this won't compile?

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

In contrast this is how I make it work:

InterfaceA := ImplementsAB as InterfaceB;

or

InterfaceA := InterfaceB;

I mean, if IInterfaceB inherits from IInterfaceA and TImplementsAB implements IInterfaceB, it wouldn't be logical to also implement IInterfaceA and be type compatible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

跨年 2024-12-27 20:00:49

这是因为早期的 OLE/COM 有一个错误,Borland 决定与其兼容。本文提到了这一点:新的 Delphi 语言功能:Delphi for .NET 中接口的多重继承 。解决方案是在类中显式列出所有祖先接口,如 Mikael 所写。

链接文章中的一些引用:

问题出在 COM 本身。为了加载模块,COM 将加载 DLL,在应该从 DLL 导出的众所周知的入口点上 GetProcAddress,调用 DLL 函数来获取 IUnknown 接口,然后调用 IClassFactory 的 QueryInterface。问题是,当 Microsoft 添加对 IClassFactory2 的支持时,他们在查询 IClassFactory 的现有代码之后添加了 IClassFactory2 的 QueryInterface。仅当查询 IClassFactory 失败时才会请求 IClassFactory2。

因此,COM 永远不会在同时实现 IClassFactory2 和 IClassFactory 的任何 COM 服务器上请求 IClassFactory2。

这个 bug 在 COM 中存在很长时间了。微软表示,他们无法使用操作系统服务包修复 COM 加载程序,因为 Word 和 Excel(当时)都依赖于错误行为。无论它是否在最新版本的 COM 中得到修复,Borland 都必须提供某种方法来在可预见的将来在 Win32 Delphi 中保留这种行为。突然将所有祖先添加到以前不存在的实现类中很可能会破坏现有代码,这些代码无意中落入与 COM 加载程序相同的模式。

This so because early OLE/COM had a bug and Borland decided to be compatible with it. This is mentioned in this article: New Delphi language feature: Multiple inheritance for interfaces in Delphi for .NET. The solution is to list all ancestor interfaces explicitly in the class as Mikael wrote.

Some quotes from the linked article:

The problem was in COM itself. To load a module, COM would load the DLL, GetProcAddress on a well-known entry point that was supposed to be exported from the DLL, call the DLL function to obtain an IUnknown interface, and then QueryInterface for IClassFactory. The problem was, when Microsoft added support for IClassFactory2, they added the QueryInterface for IClassFactory2 after the existing code that queried for IClassFactory. IClassFactory2 would only be requested if the query for IClassFactory failed.

Thus, COM would never request IClassFactory2 on any COM server that implemented both IClassFactory2 and IClassFactory.

This bug existed in COM for a long time. Microsoft said that they couldn't fix the COM loader with an OS service pack because both Word and Excel (at the time) relied on the buggy behavior. Regardless of whether it's fixed in the latest releases of COM or not, Borland has to provide some way to preserve this behavior in Win32 Delphi for the forseeable future. Suddenly adding all ancestors into an implementing class that weren't there before is very likely to break existing code that unintentionally falls into the same pattern as the COM loader.

反差帅 2024-12-27 20:00:49

使其工作的另一种方法是将两个接口都包含在类声明中。

TImplementsAB = class(TSingletonImplementation, IInterfaceA, IInterfaceB)
  procedure DoA;
  procedure DoB;
end;

我想这就是编译器认识到 TImplementsAB 实现 IInterfaceAIInterfaceB 所需要的。

Another way to make it work is to include both interfaces in the class declaration.

TImplementsAB = class(TSingletonImplementation, IInterfaceA, IInterfaceB)
  procedure DoA;
  procedure DoB;
end;

I guess this is what is required for the compiler to realize that TImplementsAB implements both IInterfaceA and IInterfaceB.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文