Сбой объекта в основной программе, но не при перемещении в модуль - PullRequest
2 голосов
/ 27 января 2010

Я написал собственный инструментарий графического интерфейса SDL (исходный код http://sourceforge.net/projects/lkgui/files/), и у меня возникла проблема с унаследованным объектом.

Когда объект находится в основной программе, конструктор не вызывается, поэтому программа не инициализирует объект должным образом и после некоторых команд вылетает (в частности, TStartGameButton наследует от GUI_Canvas, наследует от GUI_Element и все, что не определено в GUI_Element вылетает программа с EAccessViolation). Когда объект помещается в единицу, эта проблема исчезает.

Я понимаю, что я мог бы просто оставить его в модуле, но это приведет к некоторому уродливому коду, который, можно надеяться, можно будет избежать.

Кто-нибудь знает, почему это может происходить и как мне этого избежать?

Ответы [ 2 ]

3 голосов
/ 27 января 2010

Объекты Delphi старого стиля были повреждены с момента выпуска Delphi 2, возможно, ранее. Они не очень хорошо наследуют, когда имеют поля управляемых компилятором типов, таких как string или динамические массивы. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *2004* * * * * * * * * * * * * . Вот код для его воспроизведения:

type
  TBase = object
  public
    s: string;
  end;

  TDerived = object(TBase)
  end;

procedure test;
var
  obj: TDerived; //okay for TBase!
begin
  assert(obj.s = '', 'uninitialized dynamic variable');
end;

И на самом деле это нормально только для TBase случайно из-за того, как генерируется код пролога функции. Добавление дополнительного кода в эту функцию может привести к ее краху в любом случае.

Действительно, это именно то, что вы заметили - объекты старого стиля не инициализируются должным образом. Их строковые поля не начинаются с пустой строки; вместо этого они содержат мусор, и поэтому даже невозможно инициализировать их самостоятельно, не используя что-то вроде FillChar.

Вероятно, это связано с тем, что переменные локальные переменные. Переменные области видимости («глобальные») работают нормально. Переменные, которые объявлены в области видимости модуля, но используются только разделом инициализации модуля или в области программы и используются только в основном блоке начала и конца файла DPR, обрабатываются компилятором как локальные переменные, поэтому они не устанавливаются для всех -бит-ноль, как их глобальные аналоги. Когда вы перемещаете объявление переменной в единицу, но продолжаете использовать ее в файле DPR, оно переводится в «глобальный» статус.

Ваш тип TGUI_Element имеет член string с именем DbgName, и похоже, что это единственное строковое поле в иерархии типов. Уберите это или измените на ShortString, и я уверен, что ваши сбои исчезнут, по крайней мере, временно.

0 голосов
/ 27 января 2010

Почему вы даете всем объектам индивидуальные именованные конструкторы, а не делаете их виртуальными?

  type   tx = object
                constructor init; virtual;
                end;
         txx = object(tx)
                   constructor init; virtual; // like override in Delphi classes.
                  end;

Если вам нужна визуальная иерархия, посмотрите на Free Vision, она демонстрирует почти каждый аспект объектной модели TP

Упс очевидно, что виртуальные конструкторы невозможны в модели TP

...