Base Delphi接口不能以多态方式工作

时间:2011-06-29 13:41:13

标签: delphi delphi-7

我创建了几个接口来描述集合及其项目:IetCollection和IetCollectionItem。当然,我有两个实现这两个接口的类:TetCollection和TetCollectionItem(都继承自TInterfacedObject。)

然后我有一系列接口,其中顶级接口继承自IetCollectionItem,其余接口来自它(让我们称之为ISomeBasicType和ISomeSpecificType1以及ISomeSpecificType2。)

类TSomeBasicType继承自类TetCollectionItem,并且还实现了ISomeBasicType。层次结构中的其他类继承自TSomeBasicType并实现其各自的接口(即ISomeSpecificType1和ISomeSpecificType2。)

当我填充集合时,我使用工厂方法来获取对ISomeBasicType的引用。到目前为止,一切正常。

但是当我尝试遍历集合并询问集合项是否支持ISomeSpecificType1或ISomeSpecificType2时,我得到的答案是否。

我一直在努力解决这个问题,但我没有取得任何成果,所以任何帮助都会受到高度赞赏。

以下是一些代码:

// This is the basic type
IetCollectionItem = interface
end;

// Implementation of the basic type
TetCollectionItem = class(TInterfacedObject, IetCollectionItem)
end; 

ISomeBasicType = interface(IetCollectionItem)
end; 

ISomeSpecificType1 = interface(ISomeBasicType)
end; 

// Implements ISomeBasicType, should inherit implementation of IetCollectionItem
// from TetCollectionItem
TSomeBasicType = class(TetCollectionItem, ISomeBasicType)
end; 

// Implements ISomeSpecificType1, should inherit implementation of ISomeBasicType
// from TSomeBasicType and implementation of IetCollectionItem from
// TetCollectionItem
TSomeSpecificType1 = class(TSomeBasicType, ISomeSpecificType1)
end; 

这是我用户填充集合的代码:

var
  aBaseType: ISomeBasicType;
  aSpecificType: ISomeSpecificType1;
begin
  aBaseType:= TheFactory(anID, aType);  // Returns a reference to ISomeBasicType

  if Supports(aBaseType, ISomeSpecificType1, aSpecificType) then
  begin
    // Do something to the specific type
    aTypeCollection.Add(aSpecificType);
  end
  else
    aTypeCollection.Add(aBaseType);

这是失败的代码:我遍历集合,然后检查其中的任何项是否支持其中一个子接口。

var
  iCount: Integer;
  aBaseType: ISomeBasicType;
  aSpecificType: ISomeSpecificType1;
begin
  for iCount:= 0 to Pred(aTypeCollection.Count) do
  begin
    aBaseType:= aTypeCollection[iCount];

    // This is where Supports fails
    if Supports(aBaseType, ISomeSpecificType1, aSpecificType) then
    begin
    end;
  end;
end;

以下是TheFactory的代码:

function TheFactory(const anID: Integer; const aType: TetTypes): ISomeBasicType;
begin
  Result:= nil;

  case aType of
    ptType1 : Result:= TSomeSpecificType1.Create(anID, aType);
    ptType2 : Result:= TSomeSpecificType2.Create(anID, aType);
  end;

  Assert(Assigned(Result), rcUnknonwPhenomenonType);
end;  {TheFactory}

3 个答案:

答案 0 :(得分:6)

虽然你的代码让我感到头晕,但是从你的问题标题中我感觉我知道你的问题在哪里。遗憾的是,Delphi的接口多态性不像Delphi的类多态(我在某处读过这篇文章,这与以前的COM接口兼容性有关)。关键是,如果您要查询特定接口的类实例,Delphi只会找到直接在类声明中列出的接口,尽管类声明中的另一个接口可能是从您要查询的接口继承的。看到这个简单的例子来理解我的意思。 对不起,如果我的回答完全错过了你的问题。

type
  TForm61 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  IBase = interface
  ['{AE81FB3C-9159-45B0-A863-70FD1365C113}']
  end;

  IChild = interface(IBase)
  ['{515771E7-44F6-4819-9B3A-F2A2AFF74543}']
  end;

  TBase = class(TInterfacedObject, IBase)

  end;

  TChild = class(TInterfacedObject, IChild)

  end;

  TChildThatSupportsIbase = class(TChild, IBase)

  end;

var
  Form61: TForm61;

implementation

{$R *.dfm}

procedure TForm61.Button1Click(Sender: TObject);
var
  Child: IChild;
  ChildThatSupportsIbase: IChild;
begin
  Child := TChild.Create;
  ChildThatSupportsIbase:= TChildThatSupportsIbase.Create;
  if Supports(Child, IBase) then
    ShowMessage('TChild supports IBase')
  else
    ShowMessage('TChild doesn''t supports IBase');
  if Supports(ChildThatSupportsIbase, IBase) then
    ShowMessage('TChildThatSupportsIbase supports IBase')
  else
    ShowMessage('TChildThatSupportsIbase doesn''t supports IBase');
end;

答案 1 :(得分:2)

编辑示例代码以使用您的类层次结构。两个Supports调用都返回True。我只在你的界面添加了GUID。


如果我的水晶球处于正常工作状态,你就忘了给你的接口GUID了。


这是一个证据,证明你认为我认为的作品。如果这不是您要求的,请使用提示并使用简短但完整的控制台应用程序替换代码块,以清楚地显示问题:

program Project29;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type

  // This is the basic type
  IetCollectionItem = interface
  end;

  // Implementation of the basic type
  TetCollectionItem = class(TInterfacedObject, IetCollectionItem)
  end;

  ISomeBasicType = interface(IetCollectionItem)
  ['{F082CD83-5030-42EE-A1A8-FF91769F986F}']
  end;

  ISomeSpecificType1 = interface(ISomeBasicType)
  ['{8789FD5A-FC94-4F19-B28B-8ABA67D66DAE}']
  end;

  // Implements ISomeBasicType, should inherit implementation of IetCollectionItem
  // from TetCollectionItem
  TSomeBasicType = class(TetCollectionItem, ISomeBasicType)
  end;

  // Implements ISomeSpecificType1, should inherit implementation of ISomeBasicType
  // from TSomeBasicType and implementation of IetCollectionItem from
  // TetCollectionItem
  TSomeSpecificType1 = class(TSomeBasicType, ISomeSpecificType1)
  end;

var iBase: IetCollectionItem;

begin
  iBase := TSomeSpecificType1.Create;

  if Supports(iBase, iSomeBasicType) then
    WriteLn('iBase supports iSomeBasicType')
  else
    WriteLn('iBase does not support iSomeBasicType');

  if Supports(iBase, ISomeSpecificType1) then
    WriteLn('iBase supports ISomeSpecificType1')
  else
    WriteLn('iBase does not support ISomeSpecificType1');

  WriteLn('Press ENTER'); Readln;
end.

答案 2 :(得分:0)

首先,在列表中放置一些明显不支持ISomeSpecificType1的内容:

 if Supports(aBaseType, ISomeSpecificType1, aSpecificType) then
  begin
    // Do something to the specific type
    aTypeCollection.Add(aSpecificType);
  end
  else
    aTypeCollection.Add(aBaseType); //<------- this

然后你想知道为什么它不支持ISomeSpecificType1。

究竟是什么问题?为什么你认为集合中的所有项目甚至任何项目都应该支持ISomeSpecificType1?

可能是您添加的每个项目都不支持它。