Программирование - это просто
Advertisement
Главная arrow Уроки Delphi arrow Delphi изнутри arrow TObject: ClassName, Pointer, vmtClassName
25.04.2024 г.
Главное меню
Главная
Интернет магазин
Программные продукты
Биржевые роботы
Искусственный интеллект
Математика и информатика
1С:Предприятие
Уроки C#
Уроки Delphi
Уроки программирования
Web-программирование
Дизайн и графика
Компьютер для блондинок
Исходники
Статьи
Платный раздел
Рассказы про компьютеры
Хитрости и секреты
Системный подход
Размышления
Наука для чайников
Друзья сайта
Excel-это не сложно
Все о финансах
.
TObject: ClassName, Pointer, vmtClassName Печать E-mail
Автор megabax   
03.08.2009 г.
New Page 2

TObject (ClassName, Pointer, vmtClassName)

Сегодня мы изучим некоторые методы класса TObject.

Начнем с ClassName. Эта функция возвращает имя класса. Для иллюстрации ее работы рассмотрим пример:

unit ClassNameUnit;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
    TfrmClasNameDemo = class(TForm)
          btnNameClassTObject: TButton;
          btnNameChildClass: TButton;
          btnNameChildAsParent: TButton;
          procedure btnNameClassTObjectClick(Sender: TObject);
          procedure btnNameChildClassClick(Sender: TObject);
          procedure btnNameChildAsParentClick(Sender: TObject);
   private
         { Private declarations }
   public
        { Public declarations }
   end;

  TChildClass=class(TObject)
  end;

  var
  frmClasNameDemo: TfrmClasNameDemo;

implementation

{$R *.dfm}

procedure TfrmClasNameDemo.btnNameClassTObjectClick(Sender: TObject);
var obj:TObject;
begin
    obj:=TObject.Create;
    messageDlg(obj.ClassName,mtInformation,[mbOk],0);
end;

procedure TfrmClasNameDemo.btnNameChildClassClick(Sender: TObject);
var obj:TChildClass;
begin
    obj:=TChildClass.Create;
    messageDlg(obj.ClassName,mtInformation,[mbOk],0);
end;

procedure TfrmClasNameDemo.btnNameChildAsParentClick(Sender: TObject);
var obj:TObject;
begin
    obj:=TChildClass.Create;
    messageDlg(obj.ClassName,mtInformation,[mbOk],0);
end;


end.
 

TObject, ClassName, Pointer, vmtClassName, указатель

*Испытав пример, мы убедился, что даже если у нас есть переменна родительского класса и мы присваиваем ей объект дочернего класса, то все равно, функция ClassName корректно вернет имя того класса, экземпляром которого фактически является данный объект.

А теперь, давайте ради интереса посмотрим, как же реализована данная функция:

class function TObject.ClassName: ShortString;
{$IFDEF PUREPASCAL}
begin
     Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
end;
{$ELSE}
asm
    { -> EAX VMT }
    { EDX Pointer to result string }

    PUSH ESI
    PUSH EDI
    MOV EDI,EDX
    MOV ESI,[EAX].vmtClassName
    XOR ECX,ECX
    MOV CL,[ESI]
    INC ECX
    REP MOVSB
    POP EDI
    POP ESI
end;
{$ENDIF}
 

Сразу бросается в глаза {$IFDEF PUREPASCAL}. Это директива препроцессора. $IFDEF означает условную компиляцию. В зависимости от установленной опции PUREPASCAL компилятор компилирует либо строку

Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;

либо вставку на ассемблере (иными словами, непосредственно в машинных командах), которая делает в принципе, тоже самое, но гораздо быстрее. Кстати по умолчанию PUREPASCAL отключена, то есть, стандартные модули скомпилированы в режиме когда выполняются ассемблерные вставки, тоесть, в оптимизированном на скорость режим.   В настройках Delphi 7 нет опций, соответствующих данной директиве. Правда, ее можно включить вручную, для это войдем в меню "Options"*.

TObject, ClassName, Pointer, vmtClassName, указатель

В открывшемся окне перейдем на закладку Directories/Conditionals и в Conditional defines ручками впишем директиву PUREPASCAL*.

TObject, ClassName, Pointer, vmtClassName, указатель

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

Теперь разберемся, что же делает выражение

Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;

И так, функция возвращает значение, расположенное по адресу PShortString(PPointer(Integer(Self) + vmtClassName)^). Сам этот адрес у нас берется из адреса, хранящемся по адресу PPointer(Integer(Self) + vmtClassName)^. Выражение PShortString означает, что значение нужно привести к типу "указатель на короткую строку". Иными словами, по указанному адресу у нас расположен адрес, где находиться строка.

Если данное выражение "сломало вам мозг", давайте попробуем представить память компьютера как длинную предлинную дорогу по бокам которой через равные промежутки стоят столбы. Возле каждого столба стоит шкафчик с надписью "Информация". Каждый столб, и соответственно, шкафчик, пронумерован. В шкафчике может лежать не только какая то полезная информация, но так же номер другого шкафчика, где лежит искомая информация. А может лежат например, сообщение, что искомая информация находится через три шкафчика от  шкафчика с номером 123. А может вообще находиться какая нибудь дикая инструкция, что нужно пройти такое то число ящиков и дальше выполнять инструкцию, хранящуюся в том ящика, до которого вы дошли.

Грубо говоря, у нас есть переменная vmtClassName - очередной шкафчик, которая хранит смещения относительно адреса объекта (это уже другой шкафчик). Как бы данное выражение говорит нам: "от шкафчика self пройдите vmtClassName шкафчиков вперед". Вы идете к этому шкафчику и находите там информацию куда идти дальше. Но это еще не все. По указанному адресу находиться номер следующего шкафчика. Вот у нас и получился адрес адреса (двойной символ ^).

 


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


 

Последнее обновление ( 22.05.2013 г. )
 
« След.   Пред. »
 
© 2024 Программирование - это просто
Joomla! - свободное программное обеспечение, распространяемое по лицензии GNU/GPL.
Русская локализация © 2005-2008 Joom.Ru - Русский Дом Joomla!
Design by Mamboteam.com | Powered by Mambobanner.de
Я принимаю Яндекс.Деньги