.
Delphi Изнутри. Урок 8. Продолжаем изучать TObject. Функции ClassInfo, GetPropInfo, InstanceSize.
Автор megabax   
27.05.2010 г.
New Page 2

Delphi Изнутри. Урок 8. Продолжаем изучать TObject. Функции ClassInfo, GetPropInfo, InstanceSize.

Продолжим изучать TObject. Сегодня мы рассмотрим функцию ClassInfo. вот как она реализована:

class function TObject.ClassInfo: Pointer;
begin
    Result := PPointer(Integer(Self) + vmtTypeInfo)^;
end;

Как видим, метод возвращает содержимое ячейки, расположенной по адресу, смещенному на vmtTypeInfo относительно описания класса. Эта функция возвращает информацию о типе. Где ее можно применить?

Например, проверить, поддерживает ли объект заданное свойство:

function HasProperty(Obj : TObject; Prop : string) : PPropInfo;
begin
   Result := GetPropInfo(Obj.ClassInfo, Prop);
end;

Вот пример работы этой ой функции:

procedure TfrmTest.btnTestClick(Sender: TObject);
var a:TLabel;
begin
   a:=TLabel.Create(nil);
   if HasProperty(a,'Alignment')<>nil then messageDlg('Поддерживает',mtInformation,[mbOk],0);
end;

Он у нас выдаст сообщение "Поддерживает". А вот если мы напишем вот так:

procedure TfrmTest.btnTestClick(Sender: TObject);
var a:TLabel;
begin
   a:=TLabel.Create(nil);
   if HasProperty(a,'FFocusControl')<>nil then messageDlg('Поддерживает',mtInformation,[mbOk],0);
end;

То на экране ничего не увидим. FFocusControl у нас является приватным полем класса TCustomLabel, TLabel его наследует, соответственно, тоже как приватное. Но функция GetPropInfo у нас видит только свойства, объявленные как published.

Рассмотрим еще один метод класса TObject - InstanceSize. Он возвращает размер экземпляра объекта. Для иллюстрации работы класса рассмотрим пример:

TInstanceSizeTest1=class(TObject)
     FField:integer;
end;

TInstanceSizeTest2=class(TObject)
    FField:array [1..10] of double;
end;

procedure TfrmTest.btnSizeInstClick(Sender: TObject);
begin
    messageDlg(IntToStr(TInstanceSizeTest1.InstanceSize),mtInformation,[mbOk],0);
    messageDlg(IntToStr(TInstanceSizeTest2.InstanceSize),mtInformation,[mbOk],0);
end;

Данный пример выдаст два сообщения: 8 и 88 - соответственно, размеры экземпляров первого и второго класса. Как видим, второй объект у нас больше так как у него в качестве поля целый массив, а у первого только число. Стоит заметить, что InstanceSize - это не занимаемая объектом память, а именно размер его экземпляра. Определим, например, такой класса:

TInstanceSizeTest3=class(TObject)
     FField:TInstanceSizeTest2;
end;

Проверим, что же у нас вернет InstanceSize:

procedure TfrmTest.btnSizeInst2Click(Sender: TObject);
begin
   messageDlg(IntToStr(TInstanceSizeTest3.InstanceSize),mtInformation,[mbOk],0);
end;

Ответ 8, хотя, казалось бы, у нас есть поля на класс, размером целых 88 байт. Но, дело в том, что храниться то в классе экземпляре TInstanceSizeTest3 не сам объект класса TInstanceSizeTest2 а только указатель на его. Теперь поняли, в чем разница между InstanceSize и объемом занимаемой памяти?

Скажу более, объекта класса TInstanceSizeTest2 , на которое указывает FField может даже не существовать, а FField быть равным nil.

Ну, и на последок посмотрим, а как же устроена функция InstanceSize:

class function TObject.InstanceSize: Longint;
begin
     Result := PInteger(Integer(Self) + vmtInstanceSize)^;
end;

Как видим, принцип работы аналогичный многим другим функциям TObject - обращение к определенному адресу по его смещению. Кстати, конкретные размеры смещений вы можете посмотреть в модуле System*:

Delphi Изнутри. Урок 8. Продолжаем изучать TObject. Функции ClassInfo, GetPropInfo, InstanceSize.

 


Скриншоты, помеченные знаком * , являются цитатами и иллюстрациями  программного продукта "Delphi", авторское право на который принадлежит "Borland Software Corporation".


Последнее обновление ( 30.05.2013 г. )