(delphi11最新学习资料) Object Pascal 学习笔记---第11章第1节(混合引用中的错误)

发布于:2024-05-07 ⋅ 阅读:(26) ⋅ 点赞:(0)
11.1.3 混合引用中的错误

​ 在使用对象时,你通常应该只使用对象变量或接口变量来访问它们。混合使用这两种方法会破坏对象 Pascal 所提供的引用计数机制,并可能导致极难跟踪的内存错误。在实践中,如果你决定使用接口,你可能应该只使用基于接口的变量。

​ 下面是许多可能的类似情况中的一个例子。假设你有一个接口、一个实现接口的类和一个将接口作为参数的全局过程:

type
  IMyInterface = interface
    ['{F7BEADFD-ED10-4048-BB0C-5B232CF3F272}']
    procedure Show;
  end;

TMyIntfObject = class(TInterfacedObject, IMyInterface)
public
  procedure Show;
end;

procedure ShowThat(AnIntf: IMyInterface);
begin
  AnIntf.Show;
end;

​ 这段代码看起来相当琐碎,而且百分之百正确,但可能出错的地方是你调用过程的方式(该代码是 IntfError 示例的一部分):

procedure TForm1.BtnMixClick(Sender: TObject);
var
  AnObj: TMyIntfObject;
begin
  AnObj := TMyIntfObject.Create;
  try
    ShowThat(AnObj);
  finally
    AnObj.Free;
  end;
end;

​ 在这段代码中发生的情况是,我将一个普通对象传递给了一个期待接口的函数。鉴于对象确实支持接口,编译器在调用时没有问题。问题出在内存管理方式上。

​ 起初,对象的引用计数为零,因为没有接口指向它。进入 ShowThat 过程后,引用计数增加到 1。现在,在退出存储过程时,引用计数减少并归零,因此对象被销毁。换句话说,当你将 AnObj 传递给过程时,它就会被销毁,这确实有点尴尬。如果运行这段代码,就会出现内存错误。

​ 这种问题可以有多种解决方案。你可以人为地增加引用计数并使用其他低级技巧。但真正的解决办法是不要将接口和对象引用混用,而只使用接口来引用对象(此代码再次取自 IntfError 示例):

procedure TForm1.BtnIntfOnlyClick(Sender: TObject); 
var
	AnIntf: IMyInterface;
begin
	AnIntf := TMyIntfObject.Create;
	ShowThat(AnIntf);
end;

​ 在这种特定情况下,解决方案非常简单,但在许多其他情况下,却很难编写出正确的代码。同样,经验法则是避免混合使用不同类型的引用。不过,请继续阅读下一节,了解一些最新的替代方法。