为什么我的班级实现子接口,而不实现其父接口? [英] Why does my class implement child interfaces, but not their parents?

查看:103
本文介绍了为什么我的班级实现子接口,而不实现其父接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Delphi中使用接口继承时,我发现了(至少对我来说)意外的行为。

I found a (at least for me) unexpected behavior when using interface inheritance in Delphi.

我有一个简单的类和接口层次结构:

I have this simple class and interface hierarchy:

+---------------+
| << IMyBase >> |
+---------------+
        ^
        |
+---------------+
| << IMyIntf >> |
+---------------+
        ^
        |
   +---------+
   | TMyObj  |
   +---------+

我想声明一个变量 IMyBase 类型。创建一个 TMyObj 并将其分配给我的变量。 IHMO,这是正常的OOP做法。

I wanted to declare a variable of type IMyBase. Create a TMyObj and assign it to my variable. IHMO this is normal OOP practice. But it turned out that it does not compile.

我也试图声明类型为 IMyIntf 的变量,并且检查它是否支持 IMyBase ,恕我直言,它应该支持它,但是不支持。

I Have also tried to declare a variable of type IMyIntf and check if it supports IMyBase, IMHO it should support it, but it doesn't.

这很简单测试代码:

program interface_inheritance;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  IMyBase = interface
    ['{CC7C61B8-3FBA-481F-AF0D-A93C603B5202}']
    procedure Hello;
  end;

  IMyIntf = interface(IMyBase)
    ['{01CE01D9-A753-431C-A30E-64BAEC6C4E26}']
    //
  end;

  TMyObj = class(TInterfacedObject, IMyIntf)
    procedure Hello;
  end;

{ TMyObj }

procedure TMyObj.Hello;
begin
  Writeln('Hello World');
end;

var
  b: IMyBase;
  i: IMyIntf;
begin
(*  // Compile Error E2010
  b := TMyObj.Create;
  b.Hello;*)

  // Does not work as Expected
  // Does not call Hello()
  i := TMyObj.Create;
  if Supports(i, IMyBase, b) then begin
    // Why does i not support IMyBase ??
    b.Hello;
  end;

  // Works but unsafe!
  // Hard cast, without check.
  i := TMyObj.Create;
  b := IMyBase(i);
  b.Hello;

  // Works, of course!
  i := TMyObj.Create;
  i.Hello;

  Readln;
end.

您可以看到我有一个有效的类/接口结构。但某些部分无法编译。

As you can see i have a valid class/interface structure. but some parts do not compile. and some do not execute as expected.


  1. 为什么 b:= TMyObj.Create; 给出不兼容的类型错误?

  2. 为什么 Supports(i,IMyBase,b)返回 false

  3. 还有另一种(更好的)方法来解决这样的问题吗?没有硬核没有检查? (如果我是IMyBase,则不起作用,因为接口不支持 is 运算符。)

  1. Why does b := TMyObj.Create; give an incompatible type error?
  2. Why does Supports(i, IMyBase, b) returns false?
  3. Is there another (better) way to solve such a problem? without a hard cast without check? (if i is IMyBase does not work, because interfaces do not support is operator.)

这是有效的Pascal / Delphi行为还是错误?恕我直言 Supports()应该返回 true 。和 TMyObj 应该是有效的 IMyBase (因此是可分配的)。

Is this valid Pascal/Delphi behavior or a bug? IMHO Supports() should return true. and TMyObj should be a valid IMyBase (and therefor be assignable).

推荐答案

这似乎有点反常,但是您的类也必须声明它也实现了父接口。您的类声明必须是这样的:

This might seem a little counter intuitive, but your class must declare that it implements the parent interface, too. Your class declaration must be like so:

TMyObj = class(TInterfacedObject, IMyBase, IMyIntf)

前Borland工程师Danny Thorpe在有关问题的答案

Danny Thorpe, a former Borland engineer, explained the rationale behind this behaviour in an answer to a related question:


如果实现类未声明其支持
继承的接口,则该类将不会与继承的接口的变量分配兼容的
。您发布的
的代码示例应该可以正常工作(使用IChild接口),但是如果您尝试从TMyClass实例中将
分配给IParent变量,那么
将会遇到麻烦。

If an implementing class does not declare that it supports an inherited interface, then the class will not be assignment compatible with variables of the inherited interface. The code sample you posted should work fine (using the IChild interface), but if you try to assign from an instance of TMyClass to a variable of IParent, then you'll run into trouble.

原因是因为COM和ActiveX允许
的实现实现后代接口(您的IChild),但拒绝其中的祖先
接口(IParent)。由于Delphi接口旨在使
与COM兼容,因此这就是愚蠢的产物的来源。

The reason is because COM and ActiveX allow an implementation to implement a descendent interface (your IChild) but deny the ancestor of that interface (IParent). Since Delphi interfaces are intended to be COM compatible, that's where this goofy artifact comes from.

这篇关于为什么我的班级实现子接口,而不实现其父接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆