На этом шаге мы рассмотрим использование классовых методов.
Классовые методы - это методы, которые оперируют собственно с классом, а не с объектами класса. Для описания заголовков таких методов используется зарезервированное слово class, которое ставится перед словами procedure и function.
Классовый метод может быть вызван с помощью ссылки на имя класса или с помощью ссылки на имя конкретного объекта. Во втором случае класс объекта передается как параметр Self.
program Project1; type TMyFirstClass = class class function GetParentName: string; end; TMySecondClass = class (TMyFirstClass) end; var MyVar: TMySecondClass; S: string; class function TMyFirstClass.GetParentName: string; begin GetParentName := Self.ClassParent.ClassName end; begin S := TMyFirstClass.GetParentName; { вызов ссылкой на класс } Writeln ('The Parent of TMyFirstClass is ', S); S := TMySecondClass.GetParentName; { вызов ссылкой на класс } Writeln ('The Parent of TMySecondClass is ', S); MyVar := TMySecondClass.Create; S := MyVar.GetParentName; { вызов ссылкой на объект } Writeln ('The Parent of MyVar is ', S); MyVar.Free; Readln; end.
Данная программа работает в режиме консоли MS DOS, на которую будут выведены следующие строки:
Рис.1. Результат работы приложения
Рассмотрим, что же означает фраза "оперируют собственно с классом".
Во время выполнения программы для каждого класса в памяти хранится информация о его типе - так называемая информация о типе времени выполнения (Run-Time Type Information, сокращенно RTTI). И классовые методы предназначены для организации доступа к этой информации.
Для работы с RTTI в Object Pascal есть еще один способ - с помощью указателей на классы, которые фактически являются указателями на RTTI. Для описания указателей на классы используются зарезервированные слова class of.
В качестве примера приведем программу, работающую в консольном режиме, в которой объявляются три указателя на классы: PtrMyFirstClass указывает на класс TPtrMyFirstClass, PtrMySecondClass указывает на класс TPtrMySecondClass, PtrTObject указывает на класс TObject. Напомним, что TClass является предопределенным типом указателей на класс TObject. С помощью этих указателей выполняется вызов классового метода ClassName, который описан в классе TObject и возвращает имя своего класса. Кроме того, в этом примере демонстрируется совместимость указателей на классы, согласно правилам которой, указателю на родительский класс можно присваивать адреса классов-потомков, но не наоборот. Благодаря этому, посредством указателя на главный класс TObject, можно извлечь из RTTI имена любых используемых в программе классов.
program Project2; type TMyFirstClass = class end; TMySecondClass = class (TMyFirstClass) end; TPtrMyFirstClass = class of TMyFirstClass; TPtrMySecondClass = class of TMySecondClass; var PtrMyFirstClass : TPtrMyFirstClass; PtrMySecondClass : TPtrMySecondClass; PtrTObject : TClass; S : string; begin { Указатель PtrTObject может указывать как на свой класс } { TObject, так и на его классы-потомки TMyFirstClass и } { TMySecondClass. } PtrTObject := TObject; S := PtrTObject.ClassName; Writeln ('PtrTObject can point to class ', S); PtrTObject := TMyFirstClass; S := PtrTObject.ClassName; Writeln ('PtrTObject can point to class ', S); PtrTObject := TMySecondClass; S := PtrTObject.ClassName; Writeln ('PtrTObject can point to class ', S); Writeln; { Указатель PtrMyFirstClass может указывать как на свой } { класс TMyFirstClass, так и на его класс-потомок } { TMySecondClass. } PtrMyFirstClass := TMyFirstClass; S := PtrMyFirstClass.ClassName; Writeln ('PtrMyFirstClass can point to class ', S); PtrMyFirstClass := TMySecondClass; S := PtrMyFirstClass.ClassName; Writeln ('PtrMyFirstClass can point to class ', S); Writeln; { Указатель PtrMySecondClass может указывать только на } { свой класс. } PtrMySecondClass := TMySecondClass; S := PtrMySecondClass.ClassName; Writeln ('PtrMySecondClass can point to class ', S); Readln end.
После запуска этой программы получим следующий результат:
Рис.2. Результат работы приложения
На следующем шаге мы рассмотрим операции is и as.