gpt4 book ai didi

delphi - 如何在delphi控件中实现接口(interface)

转载 作者:行者123 更新时间:2023-12-03 15:24:51 25 4
gpt4 key购买 nike

我读到,如果一个类实现了一个接口(interface),那么它现在是引用计数的,并且不应该通过调用 free 来管理其内存。

但是,如果您创建一个自定义控件并让它实现一个接口(interface),那么如何防止其所有者管理其内存?例如,当您在设计时将其放在表单上时,引用计数和所有者内存管理会发生冲突吗?

感谢您的宝贵时间。

最佳答案

控件不属于此行为,因为它们不是从 TInterfacedObject 继承的。
因此,它们不进行引用计数,它们的引用计数在设计上固定在 -1*)

所有控件都继承自 TComponent,如下所示:

TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)  

TComponent 中的引用计数如下所示:

function TComponent._AddRef: Integer;
begin
if FVCLComObject = nil then Result := -1
// -1 indicates no reference counting is taking place
else Result := IVCLComObject(FVCLComObject)._AddRef;
end;

function TComponent._Release: Integer;
begin
if FVCLComObject = nil then Result := -1
// -1 indicates no reference counting is taking place
else Result := IVCLComObject(FVCLComObject)._Release;
end;

*)需要注意的是,如果分配了 VCLComObject,它们会遵循该对象的引用计数(通常不会停留在 -1)。
对于大多数组件,VCLComObject 为零。
它仅用于 IDE 生成的组件包装器来包装 COM 对象。
See: TComponent.ComObject

因此您可以随心所欲地添加界面。只要您记得在完成后释放组件,它就可以正常工作。

您可以通过测试来测试控件是否执行引用计数:

DoesNotRefCount:= Supports(MyObject, IInterfaceComponentReference) 
and (TComponent(MyObject).VCLComObject = nil);

请勿在对象上调用 _AddRef 来测试它是否返回 -1,因为这可能会破坏使用引用计数的对象。
如果您的引用计数对象从 0 开始,并且执行 _AddRef 后跟 _Release,您将销毁该对象,即使 Delphi 正要调用 _AddRef 下面有两条指令。

如果您想创建自己的不进行引用计数的对象,那么添加一个标记接口(interface)可能是一个好主意:

INoRefCounting = interface
['{CAD60ADF-C49A-46FB-BB5A-CC54BD22C7EB}']
end;

在较新的 Delphi 中,您可以从 TSingletonImplementation 继承,它为您进行虚拟无引用计数。
在较旧的 Delphi 中,继承自 TObject(或 TWhatever)并实现无引用计数,如下所示:

function TMyObject.QueryInterface(const IID: TGUID; out Obj): HResult; {stdcall;}
begin
if GetInterface(IID, Obj) then Result := S_OK
else Result := E_NOINTERFACE;
end;

function TMyObject._AddRef: Integer; {stdcall;}
begin
Result := -1;
end;

function TMyObject._Release: Integer; {stdcall;}
begin
Result := -1;
end;

最后说明
如果您想 100% 确定您的自定义控件不执行引用计数,则必须重写 _AddRef/_Release 方法,以基于以下条件删除条件引用计数: VCLComObject

警告
如果控件的生命周期很短,并且您仍然保留对这些控件的接口(interface)的引用较长时间,那么您就会遇到问题。
如果您遇到此问题,可能值得将调试代码添加到您跟踪引用的 _AddRef_ReleaseDestroy 方法中如果重新计数达到零太晚或太快,则进行计数并发出信号。

关于delphi - 如何在delphi控件中实现接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36754430/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com