Как наследовать от TObjectList вместо наследования от TObjectList
почему эта программа сообщает об утечках памяти?
{$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.
2 ответов
вы вызываете конструктор без параметров TObjectList<T>. Это фактически конструктор TList<T>, класса TObjectList<T> происходит. 
все конструкторы объявлены в TObjectList<T> принимает параметр с именем AOwnsObjects, который используется для инициализации OwnsObjects собственность. Потому что вы обходите этот конструктор,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.
возможно, лучшим вариантом было бы сделать так, чтобы ваш конструктор также предлагал :
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> is называемый. 
на документация имеет эту информацию:
зарезервированное слово inherited играет особую роль в реализации полиморфного поведения. Это может происходить в определениях методов, с идентификатором или без него.
если за наследуемым следует имя элемента, он представляет собой обычный вызов метода или ссылку на свойство или поле, за исключением того, что поиск ссылочного элемента начинается с непосредственный предок класса метода enclosing. Например, когда:
inherited Create(...);происходит в определении метода, он вызывает унаследованное Create.
когда унаследованный не имеет идентификатора после него, он ссылается на унаследованный метод с тем же именем, что и метод enclosing, или, если метод enclosing является обработчиком сообщений, на унаследованный обработчик сообщений для того же сообщения. В этом случае inherited не принимает явных параметров, но переходит к унаследованный метод те же параметры,с которыми был вызван метод enclosing. Например:
inherited;часто встречается в реализации конструкторов. Он вызывает унаследованный конструктор с теми же параметрами, которые были переданы наместнику.
вы можете использовать дженерики. Это отлично работает без литья типа и утечки памяти (TObjectList<T> или TObjectDictionary<T> списки уничтожают внутренние объекты автоматически по свободной команде).
несколько советов:
- TObjectList<TPerson>-- уничтожить список лиц автоматически на free like- membersList.Free;
- TList<TPerson>-- не уничтожайте список лиц. Вы должны создать деструктор и освободить вручную каждого человека в списке;
вот пример кода (использование нового конструктора, отсутствие утечки памяти и обратная совместимость со старым кодом-см. GetPerson):
    type
      TPerson = class
      public
        Name: string;
        Age: Integer;
        function Copy: TPerson;
      end;
      TMembers = class(TObjectList<TPerson>)
      private
        function GetPerson(i: Integer): TPerson;
      public
        property Person[i: Integer]: TPerson read GetPerson;
        constructor Create(SourceList: TMembers); overload;
      end;
    { TPerson }
    function TPerson.Copy: TPerson;
    var
      person: TPerson;
    begin
      person := TPerson.Create;
      person.Name := Self.Name;
      person.Age := Self.Age;
      Result := person;
    end;
    { TMembers }
    constructor TMembers.Create(SourceList: TMembers);
    var
      person: TPerson;
    begin
      inherited Create;
      for person in SourceList do
      begin
        Self.Add(person.Copy);
      end;
    end;
    function TMembers.GetPerson(i: Integer): TPerson;
    begin
      Result := Self[i];
    end;
    procedure TForm21.Button1Click(Sender: TObject);
    var
      person: TPerson;
      memsList1: TMembers;
      memsList2: TMembers;
    begin
      // test code
      memsList1 := TMembers.Create;
      person := TPerson.Create;
      person.Name := 'name 1';
      person.Age := 25;
      memsList1.Add(person);
      person := TPerson.Create;
      person.Name := 'name 2';
      person.Age := 27;
      memsList1.Add(person);
      memsList2 := TMembers.Create(memsList1);
      ShowMessageFmt('mems 1 count = %d; mems 2 count = %d', [memsList1.Count, memsList2.Count]);
      FreeAndNil(memsList1);
      FreeAndNil(memsList2);
    end;
