суббота, 19 мая 2012 г.

Ссылки на класс

Перевод раздела Class References из справочной системы Delphi

Тип ссылки на класс

Тип ссылки на класс иногда называют метаклассом, а его объявление имеет вид:

class of type

где type – это любой класс. Идентификатор type обозначает значение, тип которого – это тип класса. Если type1 является предком type2, тогда тип class of type2 совместим по присваиванию с типом class of type1. То есть:


 type TClass = class of TObject;
 var AnyObj: TClass;

объявляет переменную AnyObj, которая может содержать ссылку на любой класс. (Объявление типа ссылки на класс не может производиться непосредственно при объявлении переменной или в списке параметров.) Вы можете присвоить переменной типа ссылка на класс значение nil.

Чтобы понять как можно использовать этот тип, рассмотрим объявление конструктора Classes.TCollection (в модуле Classes):

 type TCollectionItemClass = class of TCollectionItem;
      ...
 constructor Create(ItemClass: TCollectionItemClass);

Это объявление говорит, что для создание экземпляра Classes.TCollection, вам необходимо передать конструктору имя класса, наследуемого от Classes.TCollectionItem.

Ссылки на класс полезны, когда вам необходимо выполнить метод класса или виртуальный конструктор для класса или объекта, тип которого неизвестен на этапе компиляции.


Конструкторы и ссылки на класс

Конструктор может быть вызван при помощи переременной, содержащей ссылку на класс. Это делает возможным создание объектов, тип которых неизвестен на этапе компиляции. Например:

 
 type TControlClass = class of TControl;
 
 function CreateControl(ControlClass: TControlClass;
     const ControlName: string; X, Y, W, H: Integer): TControl;
   begin
     Result := ControlClass.Create(MainForm);
     with Result do
       begin
         Parent := MainForm;
         Name := ControlName;
         SetBounds(X, Y, W, H);
         Visible := True;
       end;
   end;

Функция CreateControl требует параметр для определения типа элемента управления, который необходимо создать. Она использует этот параметр, чтобы вызвать конструктор класса. Поскольку идентификаторы классов представляют собой значения типа ссылки на класс, при вызове CreateControl можно указать идентификатор класса чтобы создать его экземпляр. Например:

 CreateControl(TEdit, 'Edit1', 10, 10, 100, 20);

Конструкторы, вызываемые при помощи ссылок на класс, обычно являются виртуальными. Реализация конструктора, подключаемая при вызове, зависит от типа, который будет передан в процессе выполнения программы.


Операторы классов

Методы классов работают со ссылками на класс. Каждый класс наследует от TObject два метода: ClassType и ClassParent. Эти методы возвращают соответственно ссылки на класс объекта и класс его непосредственного предка. Оба метода возвращают значение типа TClass (где TClass = class of TObject), которое может быть преобразовано к типу определенного класса. Каждый класс наследует метод InheritsFrom, который выполняет проверку наследования от определенного класса. Эти методы используются операторами is и as,.что позволяет не вызывать их в обычной ситуации.


Оператор is

Проверяющий оператор is, применяется для определения класса объекта в режиме выполнения программы. Выражение

 object is class

возвращает True если object – это экземпляр типа class или любого из его предков. В противном случае он возвращает False. (Если object имеет значение nil, оператор вернет False.) Если объявленный тип объекта не имеет отношения к классу, то есть классы отличаются, и проверяемый класс не является предком класса экземпляра, происходит ошибка компиляции. Например:

 if ActiveControl is TEdit then TEdit(ActiveControl).SelectAll;

Эта инструкция после проверки принадлежности объекта к классу TEdit (или какому-либо его потомку) преобразует переменную к типу TEdit.


Оператор as

Оператор as выполняет безопасное преобразование типов. Выражение вида

 object as class

возвращает ссылку на объект object, который имеет тип, преобразованный к class. При выполнении программы объект должен быть экземпляром класса class, его потомка, или иметь значение nil. В противном случае возникает исключительная ситуация. Если при компиляции объявленный тип объекта object не имеет отношения к class – то есть ни один из типов не является предком другого типа – возникает ошибка компиляции. Например:

 
 with Sender as TButton do
  begin
   Caption := '&Ok';
   OnClick := OkClick;
  end;

Правила приоритета операторов зачастую требуют, чтобы преобразование типов при помощи оператора as заключалось в скобки:

 
(Sender as TButton).Caption := '&Ok';

Комментариев нет:

Отправить комментарий