delphi - 如何继承TObjectList<T>而不是继承TObjectList

标签 delphi inheritance generic-collections

为什么这个程序报告内存泄漏?

{$APPTYPE CONSOLE}

uses
  System.Generics.Collections;

type
  TDerivedGenericObjectList = class(TObjectList<TObject>)
  public
    constructor Create;
  end;

constructor TDerivedGenericObjectList.Create;
begin
  inherited;
end;

var
  List: TDerivedGenericObjectList;

begin
  ReportMemoryLeaksOnShutdown := True;
  List := TDerivedGenericObjectList.Create;
  List.Add(TObject.Create);
  List.Free;
end.

最佳答案

您正在调用 TObjectList<T> 的无参数构造函数。这实际上是 TList<T> 的构造函数,来自 TObjectList<T> 的类(class)是衍生出来的。

TObjectList<T> 中声明的所有构造函数接受名为 AOwnsObjects 的参数用于初始化 OwnsObjects属性(property)。因为您正在绕过该构造函数,OwnsObjects默认为False ,并且列表中的成员不会被销毁。

您应该确保调用 TObjectList<T> 的构造函数初始化OwnsObjects 。例如:

{$APPTYPE CONSOLE}

uses
  System.Generics.Collections;

type
  TDerivedGenericObjectList = class(TObjectList<TObject>)
  public
    constructor Create;
  end;

constructor TDerivedGenericObjectList.Create;
begin
  inherited Create(True);
end;

var
  List: TDerivedGenericObjectList;

begin
  ReportMemoryLeaksOnShutdown := True;
  List := TDerivedGenericObjectList.Create;
  List.Add(TObject.Create);
  List.Free;
end.

也许更好的变体是让您的构造函数也提供 AOwnsObjects参数:

type
  TDerivedGenericObjectList = class(TObjectList<TObject>)
  public
    constructor Create(AOwnsObjects: Boolean = True);
  end;

constructor TDerivedGenericObjectList.Create(AOwnsObjects: Boolean);
begin
  inherited Create(AOwnsObjects);
end;

或者:

type
  TDerivedGenericObjectList = class(TObjectList<TObject>)
  public
    constructor Create(AOwnsObjects: Boolean = True);
  end;

constructor TDerivedGenericObjectList.Create(AOwnsObjects: Boolean);
begin
  inherited;
end;
<小时/>

所以,您可能想知道为什么原始版本选择了 TList<T>构造函数而不是 TObjectList<T> 中的构造函数。好吧,让我们更详细地看一下。这是您的代码:

type
  TDerivedGenericObjectList = class(TObjectList<TObject>)
  public
    constructor Create;
  end;

constructor TDerivedGenericObjectList.Create;
begin
  inherited;
end;

何时 inherited以这种方式使用时,编译器会查找与此签名完全相同的构造函数。它在 TObjectList<T> 中找不到一个因为它们都有参数。它可以在 TList<T> 中找到一个,所以这就是它使用的那个。

正如您在评论中提到的,以下变体不会泄漏:

constructor TDerivedGenericObjectList.Create;
begin
  inherited Create;
end;

此语法与纯粹的 inherited 相比,将找到替换默认参数时匹配的方法。所以 TObjectList<T> 的单参数构造函数叫做。

documentation有以下信息:

The reserved word inherited plays a special role in implementing polymorphic behavior. It can occur in method definitions, with or without an identifier after it.

If inherited is followed by the name of a member, it represents a normal method call or reference to a property or field, except that the search for the referenced member begins with the immediate ancestor of the enclosing method's class. For example, when:

inherited Create(...);

occurs in the definition of a method, it calls the inherited Create.

When inherited has no identifier after it, it refers to the inherited method with the same name as the enclosing method or, if the enclosing method is a message handler, to the inherited message handler for the same message. In this case, inherited takes no explicit parameters, but passes to the inherited method the same parameters with which the enclosing method was called. For example:

inherited;

occurs frequently in the implementation of constructors. It calls the inherited constructor with the same parameters that were passed to the descendant.

关于delphi - 如何继承TObjectList<T>而不是继承TObjectList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32578436/

相关文章:

c# - 从子类中替换父类

java - 基本继承——需要解释一行代码

Java - 获取泛型对象作为 String 泛型类型抛出异常

c# - 清除推送列表时清除通用列表堆栈

java - 当泛型类型信息不可用时,如何避免编译器警告?

Delphi XE 和 ZLib 问题

xml - 如何在未安装 Excel 的情况下将 DBGrid 导出为 OOXML 格式(Excel 2007/2010 格式)?

delphi - 从 LocalSystem 服务运行非可视化 GUI 应用程序

c++ - Qt - 从基类继承类

delphi - 使用 ASM 调用对象方法