kdt*_*top 0 delphi polymorphism typecast-operator typecasting-operator
当使用作为传递参数的类时,我在理解类型转换方面遇到了一些困难。我尝试寻找这个但找不到其他答案。
我正在使用一些旧的 Delphi 代码,使用 Delphi 2006,它不支持泛型(在 Delphi 2009 中引入)。
该代码使用 TList 来存储指向特定类型的实例化类的指针。当清除列表时,他们使用这个:
procedure ClearList(AList: TList);
var i: Integer;
begin
for i := 0 to AList.Count - 1 do
TObject(AList[i]).Free;
AList.Clear;
end;
Run Code Online (Sandbox Code Playgroud)
它的名字是这样的:
ClearList(FExtraVisitTypes);
ClearList(FDiagnoses);
ClearList(FProcedures);
ClearList(FImmunizations);
ClearList(FSkinTests);
ClearList(FPatientEds);
ClearList(FHealthFactors);
ClearList(FExams);
Run Code Online (Sandbox Code Playgroud)
我对此的理解可能有所偏差,但我担心如果将指向的对象作为 TObject 释放,则不会调用后代对象的析构函数,从而可能导致内存泄漏。(我的多态功夫有点生疏,可能会造成我的困惑。)
所以我尝试将清除功能更改如下:
procedure ClearList(AList: TList; ItemClass: TPCEItemClass); //mod to add ItemClass
var i: Integer;
begin
for i := 0 to AList.Count - 1 do begin
(AList[i] as ItemClass).Free;
end;
AList.Clear;
end;
Run Code Online (Sandbox Code Playgroud)
TPCEItemClass 定义如下:
TPCEItemClass = class of TPCEItem;
Run Code Online (Sandbox Code Playgroud)
然后我像这样更改了清晰的调用:
ClearList(FExtraVisitTypes, TPCEProc);
ClearList(FDiagnoses, TPCEDiag);
ClearList(FProcedures, TPCEProc);
ClearList(FImmunizations, TPCEImm);
ClearList(FSkinTests, TPCESkin);
ClearList(FPatientEds, TPCEPat);
ClearList(FHealthFactors, TPCEHealth);
ClearList(FExams, TPCEExams);
Run Code Online (Sandbox Code Playgroud)
但编译器不允许这样做并给出以下错误:
[Pascal Error] uPCE.pas(1730): E2015 Operator not applicable to this operand type
Run Code Online (Sandbox Code Playgroud)
对于这个错误行:
(AList[i] as ItemClass).Free;
Run Code Online (Sandbox Code Playgroud)
问题:
原始的编码方式(通过简单地调用伟大-伟大-伟大(等)祖先 Free 方法来释放项目)是否最终会影响后代的析构函数方法?当我写这篇文章时,我现在认为它确实如此。但我不知道为什么。所以任何能帮助我记住这一点的答案都会很棒。
为什么我尝试通过类类型的参数进行类型转换的方法不起作用?难道这只是不允许的吗?或者我的语法错误?还有其他方法可以做到这一点吗?
我这一切都错了吗?有没有更好的办法?
谢谢
我担心如果将指向的对象作为 TObject 释放,则不会调用后代对象的析构函数,这可能会导致内存泄漏。
对于正确实现的类来说,情况并非如此。
所有类都派生于TObject. TObject.Free()调用TObject.Destroy()析构函数,即virtual. 任何需要破坏逻辑的后代都必须使用override该析构函数(如果没有,则它有一个需要修复的缺陷)。
因此,在正确编写的代码中,原始代码将完美地工作,如图所示。调用Free()任何有效且正确实现的对象都将调用其最派生的析构函数。
话虽这么说,多年来人们override在类需要析构函数时忘记了很多情况,从而导致了您所担心的内存泄漏。因此,请确保您关注班级正在做的事情,这样您就会没事的。
所以我尝试如下更改清除函数...但是编译器不允许这样做并给出此错误
正确,因为您无法使用变量对对象执行元类类型的类型转换,就像您尝试做的那样。类型转换要求在编译时指定目标类型,但元类变量直到运行时才会分配。
原始的编码方式(通过简单地调用伟大-伟大-伟大(等)祖先 Free 方法来释放项目)是否最终会影响后代的析构函数方法?
是的,原始代码在 99% 的情况下都可以正常工作。大多数 Delphi 程序员都擅长override在适当的时候使用析构函数。但是,另外 1% 仅在您处理未正确实现的类时出现,在这种情况下,修复它们是它们的作者的责任,而不是您修复调用它们的代码的责任Free()。
当我写这篇文章时,我现在认为它确实如此。但我不知道为什么。
虚拟析构函数的多态分派,就像调用任何其他virtual方法时一样。
为什么我尝试通过类类型的参数进行类型转换的方法不起作用?难道这只是不允许的吗?
正确的。这是非法的。
还有其他方法可以做到这一点吗?
不(嗯,是的,但它涉及在运行时手动遍历对象的类结构,但这需要深入了解编译器如何在内存中布置对象,所以我不打算在这里深入讨论)。