Шаг 146.
Классовые методы и указатели на классы

    На этом шаге мы рассмотрим использование классовых методов.

    Классовые методы - это методы, которые оперируют собственно с классом, а не с объектами класса. Для описания заголовков таких методов используется зарезервированное слово 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 создается для классов, а не для объектов, и существует отдельно от них. Поэтому к этой информации можно обращаться без предварительного создания объектов, а реализация классовых методов не должна зависеть от значений каких-либо конкретных объектов.

    Для работы с 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.




Предыдущий шаг Содержание Следующий шаг