Методы класса и указатели на класс.

Некоторые методы бывает нужно вызывать без создания экземпляра класса (например, для получения информации о имени класса, размере экземпляра класса и т.п.). Такие методы называются методами класса - в C++ и Java они называются статистическими методами (не путать со статистическими методами в смысле TP и Delphi!). Методы класса имеют перед словами procedure или function ключевое слово class (за исключением конструкторов, которые также являются методами класса, но для которых синтаксис, как мы знаем, другой):

type

tMyObj=

class

class function MyGetSize:String;

end;

var aMyObj:tMyObj;

begin

...

Label1.caption:=tMyObj.MyGetSize; {вызов метода класса tMyObj}

aMyObj:=tMyObj.Create; {вызов другого метода класса tMyObj}

Label2.caption:=aMyObj.MyGetSize; {вызов метода класса с

экземпляром класса}

...

end;

Возможно описание указателя на класс с помощью ключевой фразы class of. Это иногда требуется в программах, использующих сложную иерархию объектов, для унифицированного динамического создания, копирования и уничтожения объектов, принадлежащих разным классам. В модуле SysUtils указатель на tObject описан так:

type tObject=class;

tClass=class of tObject;

Имеются следующие важнейшие стандартные функции классов, определенные в tObject:

· class function ClassName:string — возвращает имя класса, вызвавшего объект;

· class function ClassParent:tClass — возвращает указатель на класс прародителя;

· function ClassType:tClass — возвращает указатель на класс вызвавшего объекта;

· class function ClassInfo:Pointer — возвращает указатель на структуру (запись), содержащую информацию о классе.

Также имеется ряд других стандартных функций классов.

Пример использования указателя на класс:

tMyObj=

class

...

end;

tMyObjRef=class of tMyObj;

tChildObj=

class(tMyObj)

...

end; {/class}

var

aMyObjRef:tMyObjRef;

aMyObj:tMyObj;

aChildObj:tChildObj;

После такого объявления можно проводить присваивания такого рода:

if...

then

aMyObjRef:=tMyObj; {при выполнении условия aMyObjRef

стало типом tMyObj}

else

aMyObjRef:=tChildObj; {иначе - типом tChildObj}

aMyObj:=aMyObjRef.Create; {создали объект, тип которого

определяется aMyObjRef}

Без указателей на класс пришлось бы писать вызовы конструктора Create внутри оператора if по отдельности для tMyObj и tChildObj.

Указатели на класс удобно использовать совместно с булевским оператором is, возвращающим true в случае совместимости по присваиванию объекта, указанного перед is, с экземпляром класса, упомянутого после is:

if aMyObj is tAnyObj then...;

Например, если aMyObj – кнопка типа tBatton, а в качестве tAnyObj написано tWinControl, оператор is возвратит true. Если же aMyObj – метка типа tLabel, он возвратит false,так как tLabel является потомком tControl, но не tWinControl.

Существует также специальный вариант приведения типов для объектов при помощи оператора as:

aObj1:=aObj2 as tObj1; {aObj2 вызывается в точности как экземпляр его

класса-прародителя tObj1}

aMyVar:=(aMyObj as tMyRecordObj).Data; {тут Data - свойство;

если это обычное поле, приведение не имеет смысла}

Понятно, что такое приведение возможно только к типу класса-прародителя.

Этот тип приведения очень часто используется в обработчиках событий. Например, если мы хотим изменить координату “x” элемента типа tImage, перетаскиваемого “мышью”, то в обработчике onDragOver элемента, над которым мы его перетаскиваем, надо написать

If Sender is tImage then( Sander as tImage).x=x;

При этом написать Sender.x=x нельзя, так как типом Sender является tObject, а в нем поле x не определено.