Для использования обычного программирования ООП вы всегда должны использовать class
вид .У вас будет самая мощная объектная модель в Delphi, включая интерфейс и дженерики (в более поздних версиях Delphi).
1.Записи, указатели и объекты
Записи могут быть злыми (медленное скрытое копирование, если вы забыли объявить параметр как const
, записать скрытый медленный код очистки, a fillchar
сделает любую строку в записи утечкой памяти ...), но иногда они очень удобны для доступа к двоичной структуре (например, к небольшому значению) через указатель.
Динамический массив крошечныхзаписи (например, с одним целым и одним двойным полем) будут на намного быстрее, чем TList
небольших классов;с нашей TDynArray
оболочкой вы получите высокоуровневый доступ к записям с сериализацией, сортировкой, хэшированием и т. д.
Если вы используете указатели, вы должны знать, что вы делаете,Определенно предпочтительнее придерживаться классов и TPersistent
, если вы хотите использовать волшебную «модель владения компонентами VCL».
Наследование не допускается для записей.Вам нужно либо использовать «вариант записи» (используя ключевое слово case
в его определении типа), либо использовать вложенные записи.При использовании C-подобного API вам иногда придется использовать объектно-ориентированные структуры.Использование вложенных записей или вариантов записей ИМХО гораздо менее понятно, чем в старой доброй модели наследования «объекта».
2.Когда использовать объект
Но в некоторых местах объекты являются хорошим способом доступа к уже существующим данным.
Даже объектная модель лучше, чем новая модель записи, поскольку онаобрабатывает простое наследование.
В записи в блоге прошлым летом я опубликовал некоторые возможности по-прежнему использовать объекты:
Файл отображения памяти, которыйЯ хочу очень быстро разобрать: указатель на такой объект просто великолепен, и у вас все еще есть методы под рукой;Я использую это для TFileHeader или TFileInfo, которые отображают заголовок .zip в SynZip.pas;
Структура Win32, как определено вызовом API, в который я помещаю удобные методы для простотыдоступ к данным (для этого вы можете использовать запись, но если в структуре есть какая-то объектная ориентация - что очень распространено - вам придется вкладывать записи, что не очень удобно);
Временная структура, определенная в стеке, используется только во время процедуры: я использую ее для TZStream в SynZip.pas или для наших классов, связанных с RTTI, которые отображают сгенерированный Delphi RTTI в объектно-ориентированном виде, а не какTypeInfo, который ориентирован на функцию / процедуру.Благодаря непосредственному отображению содержимого памяти RTTI наш код работает быстрее, чем использование новых классов RTTI, созданных в куче.Мы не создаем никакой памяти, которая для ORM-фреймворка, подобного нашей, хороша для своей скорости.Нам нужно много информации RTTI, но она нужна нам быстро, нам это нужно напрямую.
3.Как реализация объекта нарушена в современном Delphi
Тот факт, что объект поврежден в современном Delphi, является позором, ИМХО.
Обычно, если вы определяете запись в стеке, содержащуюнекоторые переменные с подсчетом ссылок (например, строки) будут инициализированы магическим кодом компилятора на начальном уровне метода / функции:
type TObj = object Int: integer; Str: string; end;
procedure Test;
var O: TObj
begin // here, an _InitializeRecord(@O,TypeInfo(TObj)) call is made
O.Str := 'test';
(...)
end; // here, a _FinalizeRecord(@O,TypeInfo(TObj)) call is made
Эти _InitializeRecord
и _FinalizeRecord
will "подготовить "затем" выпустить "переменную O.Str.
В Delphi 2010 я обнаружил, что иногда этот _InitializeRecord () не всегда создавался.Если запись не имеет каких-либо открытых полей, скрытые вызовы иногда не генерируются компилятором.
Просто создайте исходный код заново, и будет ...
Единственное решение, которое явыяснилось, что вместо объекта использовалось ключевое слово record.
Вот как выглядит полученный код:
/// used to store and retrieve Words in a sorted array
// - is defined either as an object either as a record, due to a bug
// in Delphi 2010 compiler (at least): this structure is not initialized
// if defined as a record on the stack, but will be as an object
TSortedWordArray = {$ifdef UNICODE}record{$else}object{$endif}
public
Values: TWordDynArray;
Count: integer;
/// add a value into the sorted array
// - return the index of the new inserted value into the Values[] array
// - return -(foundindex+1) if this value is already in the Values[] array
function Add(aValue: Word): PtrInt;
/// return the index if the supplied value in the Values[] array
// - return -1 if not found
function IndexOf(aValue: Word): PtrInt; {$ifdef HASINLINE}inline;{$endif}
end;
{$ifdef UNICODE}record{$else}object{$endif}
ужасен ... но ошибка генерации кодане происходило с тех пор ..
Полученные изменения в исходном коде невелики, но немного разочаровывают. Я обнаружил, что более старая версия IDE (например, Delphi 6/7) не может проанализировать такое объявление, поэтому иерархия классов будет нарушена в редакторе ...: (
Обратная совместимость должна включать в себя регрессионные тесты. Многие пользователи Delphi остаются с этим продуктом из-за существующего кода. Нарушающие функции очень проблематичны для будущего Delphi, ИМХО: если вам нужно переписать много кода, не стоит ли просто переключить проект на C # или Java?