Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi接口实现_Delphi_Interface_Delphi 2007_Implements - Fatal编程技术网

Delphi接口实现

Delphi接口实现,delphi,interface,delphi-2007,implements,Delphi,Interface,Delphi 2007,Implements,我希望引用计数应该在接口实现中的外部聚合对象上起作用。 如果我可以参考另一个例子: 以下是该行为的最低限度再现: program SO16210993; {$APPTYPE CONSOLE} type IFoo = interface procedure Foo; end; TFooImpl = class(TInterfacedObject, IFoo) procedure Foo; end; TContainer = class(TInterfac

我希望引用计数应该在接口实现中的外部聚合对象上起作用。 如果我可以参考另一个例子:

以下是该行为的最低限度再现:

program SO16210993;

{$APPTYPE CONSOLE}

type
  IFoo = interface
    procedure Foo;
  end;

  TFooImpl = class(TInterfacedObject, IFoo)
    procedure Foo;
  end;

  TContainer = class(TInterfacedObject, IFoo)
  private
    FFoo: IFoo;
  public
    constructor Create;
    destructor Destroy; override;
    property Foo: IFoo read FFoo implements IFoo;
  end;

procedure TFooImpl.Foo;
begin
  Writeln('TFooImpl.Foo called');
end;

constructor TContainer.Create;
begin
  inherited;
  FFoo := TFooImpl.Create;
end;

destructor TContainer.Destroy;
begin
  Writeln('TContainer.Destroy called');//this line never runs
  inherited;
end;

procedure Main;
var
  Foo : IFoo;
begin
  Foo := TContainer.Create;
  Foo.Foo;
end;

begin
  Main;
  Readln;
end.

如果不使用
implements
,而是在
TImplementor
类中实现接口,则析构函数将运行。

这里发生的是调用
TContainer.Create
并创建对象的实例。但随后将该实例分配给一个接口引用,即全局变量
Foo
。由于该变量的类型为
IFoo
,接口委托意味着实现对象是
TFooImpl
的实例,而不是
TContainer
的实例

因此,任何东西都不会引用
TContainer
的实例,它的引用计数永远不会增加,因此它永远不会被销毁

我不认为有一个非常简单的方法来解决这个问题。您可以使用
TAggregatedObject
,但它可能无法解决您的问题。这将迫使您声明
TContainer.FFoo
TFooImpl
类型,我想您不想这样做。不管怎么说,下面是重播时的样子:

program SO16210993_TAggregatedObject;

{$APPTYPE CONSOLE}

type
  IFoo = interface
    procedure Foo;
  end;

  TFooImpl = class(TAggregatedObject, IFoo)
    procedure Foo;
  end;

  TContainer = class(TInterfacedObject, IFoo)
  private
    FFoo: TFooImpl;
    function GetFoo: IFoo;
  public
    destructor Destroy; override;
    property Foo: IFoo read GetFoo implements IFoo;
  end;

procedure TFooImpl.Foo;
begin
  Writeln('TFooImpl.Foo called');
end;

destructor TContainer.Destroy;
begin
  Writeln('TContainer.Destroy called');//this line does run
  FFoo.Free;
  inherited;
end;

function TContainer.GetFoo: IFoo;
begin
  if not Assigned(FFoo) then
    FFoo := TFooImpl.Create(Self);
  Result := FFoo;
end;

procedure Main;
var
  Foo : IFoo;
begin
  Foo := TContainer.Create;
  Foo.Foo;
end;

begin
  Main;
  Readln;
end.
政府确实谈到了这一点:

用于实现委托接口的类应派生自TAggregationObject

最初,我找不到此
TAggregationObject
的任何文档。最后我意识到它实际上被命名为
TAggregatedObject
,并且是

TAggregatedObject为对象的内部对象提供功能 通过实现IInterface方法进行聚合,以委托给 控制接口

聚合对象是由多个接口组成的对象 物体。每个对象实现自己的行为和接口,但是 所有对象共享相同的引用计数,即 控制器对象。在容器模式中,控制器是 容器对象

TAggregatedObject本身不支持任何接口。但是, 是典型的聚合,它确实实现了 界面,由从它下降的对象使用。 因此,TAggregatedObject充当 实现用于创建对象的接口,这些对象是 聚合

TAggregatedObject用作创建包含 对象和连接对象。使用TAggregatedObject可以确保 对接口方法的调用委托给控制接口 总的来说

在构造函数中为指定了控制界面 TAggregatedObject,由控制器属性指示

此外,源代码注释中还有以下内容:

TAggregatedObject和TContainedObject是合适的基类 对于拟聚合或包含在 外部控制对象。当在上使用“implements”语法时 接口属性在外部对象类声明中,使用 类型来实现内部对象

由聚合对象代表 控制器不应与其他接口区分开来 由控制员提供。聚合对象不能维护 它们自己的引用计数-它们的生存期必须与 他们的管制员。为了实现这一点,聚合对象反映了 将计数方法引用到控制器

TAggregatedObject只反映对其 控制器。从这样一个聚合对象中,可以获得任何 控制器支持的接口,并且只有 控制器支持。这对于实现控制器非常有用 类,该类使用一个或多个内部对象来实现 在控制器类上声明的接口。聚合促进 跨对象层次结构实现共享

TAggregatedObject是大多数聚合对象应该继承的对象 来自,尤其是与“机具”结合使用时 语法


“我错过什么了吗?”我不知道。但我们确实是。你忘了包括代码!需要演示行为的完整程序。否则我们只能猜测。你有一些额外的引用或引用循环。添加TFirstSecond.\u AddRef和TFirstSecond.\u释放并在那里放置断点,获取引用的完整列表,并查看哪些引用未清除。问题是您的接口被委派。不知道为什么会有这种行为,问得好。我冒昧地制作了一个非常简单的演示测试用例。委托的想法是Delphi中一个很好的官方特性,但它似乎不起作用?@FabricioAraujo我最终找到了文档。有个打字错误!!我在别处发现的无数例子误导了我。引用计数必须发生在某个地方,这是非常合理的。谢谢你的回答,不客气。这对我来说是一次有趣的学习经历!Marcos Santos提出了一个在我看来非常优雅的解决方案,允许将接口实现用作常规对象和聚合对象。解决方案是将实现类从TInterfacedObject中降序,因此只要将同一个实现与关键字implements一起使用,就可以将其用作独立对象和从TAggregatedObject中降序的装饰器。