кто-нибудь знает почему?
Потому что вы объявляете поле класса? TOrange наследуется от TFruit, поэтому он также имеет поле ID = 0. Затем вы переопределяете это с другим полем ID = 2. Теперь у вас есть два из них. Если вы разыгрываете TOrange в TFruit, то вы получаете унаследованное поле, это как раз тот способ доступа к ним.
Если вы используете Delphi 2010+, используйте атрибуты:
[ClassId(4)] TOrange = class(TFruit)
Но зачем вам эти идентификаторы? Вам придется вручную пометить каждый тип вашего класса, это может привести к ошибкам. Просто используйте имя класса.
var t: TOrange;
begin
writeFile(t.Classname, t.Data);
Если вы так озабочены пространством, сохраните таблицу идентификаторов классов в начале файла и динамически присваивайте идентификаторы:
procedure WriteObject(c: TObject);
var id: integer;
begin
if not GetAlreadyRegisteredClassnameId(c.Classname, id) then
id := AddClassnameToTable(c.Classname);
writeToCache(id, c.Data)
end;
procedure WriteFile()
var i: integer;
begin
for i := 0 to ObjectCount-1 do
WriteObject(objects[i]);
OutputClassnameTableToFile;
OutputObjectCacheToFile;
end;
(Конечно, игнорируя ограничения памяти здесь для демонстрационных целей, но это легко сделать и без кеша памяти)