4

我对接口有一个小问题。这是伪代码:

type
  Interface1 = interface
  end;

  Interface2 = interface
  end;

  TParentClass = class(TInterfacedObject, Interface1)
  private
    fChild : Interface2;
  public
    procedure AddChild(aChild : Interface2);
  end;

  TChildClass = class(TInterfacedObject, Interface2)
  private
    fParent : Interface2;
  public
    constructor Create(aPArent : Interface1);
  end;

任何人都可以看到缺陷吗?我需要孩子引用它的父母,但在这种情况下引用计数不起作用。如果我创建一个 ParentClass 实例并添加一个子类,则永远不会释放父类。我明白为什么了。我如何绕过它?

4

4 回答 4

10

引用计数的引用有两种语义:它充当所有权共享以及导航对象图的一种方式。

通常,您不需要在引用图中的循环中的所有链接上同时使用这两种语义也许只有父母拥有孩子,而不是相反?如果是这种情况,您可以通过将它们存储为指针来使子引用指向父弱链接,如下所示:

TChildClass = class(TInterfacedObject, Interface2)
private
  fParent : Pointer;
  function GetParent: Interface1;
public
  constructor Create(aPArent : Interface1);
  property Parent: Interface1 read GetParent;
end;

function TChildClass.GetParent: Interface1;
begin
  Result := Interface1(fParent);
end;

constructor TChildClass.Create(AParent: Interface1);
begin
  fParent := Pointer(AParent);
end;

如果保证实例树的根在某处保持活动状态,则这是安全的,即您不仅仅依赖于保持对树分支的引用并且仍然能够导航整个树。

于 2008-10-05T10:23:13.793 回答
3

好吧,在这种情况下,引用计数当然可以工作——它只是不能解决问题。

这是引用计数的最大问题——当你有一个循环引用时,你必须明确地“打破”它(例如,将一个接口引用设置为“nil”)。这也是为什么引用计数不能真正替代垃圾收集的原因——垃圾收集器知道循环可能存在,并且可以在没有从“外部”引用它们时释放这样的循环结构。

于 2008-10-05T10:14:40.067 回答
1

您必须创建一个明确取消链接正确引用的方法。在这种情况下,无法让自动引用计数正常工作。

于 2008-10-05T09:11:12.537 回答
0

在第一个示例中使用函数指针,则不存在循环引用问题。.NET 使用委托,而 VB6 使用事件。所有这些都具有不增加被指向对象的引用计数的好处。

于 2008-10-06T19:51:26.097 回答