为什么我的类实现子接口,而不是父母?

时间:2018-05-15 07:50:49

标签: delphi inheritance interface

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

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

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

我想声明一个IMyBase类型的变量。创建一个TMyObj并将其分配给我的变量。 IHMO这是正常的OOP练习。但事实证明它没有编译。

我还尝试声明类型为IMyIntf的变量,并检查它是否支持IMyBase,恕我直言,它应该支持它,但事实并非如此。

这是一个简单的测试代码:

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.

如您所见,我有一个有效的类/接口结构。但有些部分不能编译。有些没有按预期执行。

  1. 为什么b := TMyObj.Create;会出现不兼容的类型错误?
  2. 为什么Supports(i, IMyBase, b)会返回false
  3. 还有另一种(更好的)方法来解决这样的问题吗?没有检查没有硬铸? (if i is IMyBase不起作用,因为接口不支持is运算符。)
  4. 这是有效的Pascal / Delphi行为还是错误?恕我直言Supports()应该返回true。并且TMyObj应该是有效的IMyBase(因此可以分配)。

1 个答案:

答案 0 :(得分:10)

这可能看起来有点反直觉,但是你的类必须声明它也实现了父接口。您的班级声明必须如此:

TMyObj = class(TInterfacedObject, IMyBase, IMyIntf)

前Borland工程师Danny Thorpe在answer to a related question中解释了这种行为背后的理由:

  

如果实现类没有声明它支持   继承接口,那么该类将不会与赋值兼容   使用继承接口的变量。您发布的代码示例   应该工作正常(使用IChild接口),但如果你尝试   然后,从TMyClass的实例分配给IParent的变量   你会遇到麻烦。

     

原因是因为COM和ActiveX允许实现   实现一个后代接口(你的IChild),但否认祖先   该接口(IParent)。因为Delphi接口是为了   是COM兼容的,这就是这个愚蠢的神器来源。