По умолчанию все методы статические. Все ранее рассмотренные методы -статические. Такое наименование методов связано с тем, что определение и размещение ссылок на них (для вызова методов) производится на этапе компиляции и на все время выполнения программы. Это - раннее связывание.
Список формальных параметров статических методов может быть различным у метода предка и методов потомков, переопределяющих (заменяющих) этот метод предка.
Со статическим методом связан способ наследования. Если в объявлении потомка появляется метод с тем же именем, что и у предка, то в этом типе и во всех его потомках этот метод будет переопределен. Таким образом, потомки могут использовать переопределенные ими методы предка. Предок может вызвать только свои методы; методы потомков для него недоступны. Таким образом, при использовании статических методов полиморфизм распространяется от текущего уровня иерархии вниз, к потомкам.
Действия компилятора при обработке методов иерархии объектов для статических методов:
1) при вызове метода компилятор устанавливает тип объекта, вызывающего
метод;
2) затем он ищет метод в пределах этого типа; найдя его, компилятор назначает вызов этого метода;
3) если метод не найден, то компилятор рассматривает тип непосредственно
го предка и ищет метод в его объявлении:
а) если метод с таким именем найден, формируется вызов метода этого
предка;
б) если метод не найден в типе ближайшего предка, компилятор переходит
к типу предка, следующего в иерархии предков; и так до тех пор, пока
не будет найден вызванный метод;
в) если компилятор, дойдя до верхнего уровня иерархии, не найдет метод,
он выдаст сообщение об ошибке номер 44 периода компиляции:
Field identifier expected - ожидается идентификатор поля.
Это сообщение выдается, если идентификатор не соответствует имени поля переменной типа RECORD или типа OBJECT.
Существенное ограничение статических методов: если метод предка вызывает другие методы, то это могут быть только методы предка, даже если потомок имеет свои собственные методы с таким же именем метода. Этот недостаток предопределен тем, что связь объекта с методом производилась на этапе компиляции, статически, на все время выполнения программы. Этот недостаток статических методов устраняется использованием виртуальных методов.
Ограничение статических методов рассмотрим на примере программы листинга 3. Из него видно существенное ограничение статических методов: если метод (Metl объекта ObjName1) предка вызывает другие методы (Met2), то это могут быть только методы предка (objNamel .Met2), даже если потомок имеет свои собственные методы с таким же именем метода (objName2 .Met2). В примере листинга 3 оператор V2.Metl; вызывает выполнение метода ObjNamel .Metl, который вызывает метод ObjNamel .Met2, несмотря на то что тип ObjName2 имеет свой собственный метод ObjName2 .Met2. Это происходит потому что связь объекта с методом производилась на этапе компиляции. Схематично это представлено на рис. 2.
Листинг 3.Вызовы статических методов предка и потомка.
Program novirt1; Uses Crt;
Type ObjName1 = object { - объявление объекта-предка } Fl1 : integer; { - поле }
Procedure Met1; { - методы }
Procedure Met2;
End;
ObjName2 = object (ObjName1) { - объявление потомка } Procedure Met2; { - замена статического метода } End;
{ --- Методы объекта ObjName1 ------- }
Procedure ObjName1.Met1;
Begin Met2; { - вызов только метода ObjName1.Met2 !!} End;
Procedure ObjName1.Met2;
Begin FL1 := 12;
Writeln ( 'Работает метод ObjName1.Met2: FL1 = ', FL1) End;
{ ----- Метод объекта ObjName2 ------ }
Procedure ObjName2.Met2; Begin FL1 := 34;
Writeln ( 'Работает метод ObjName2.Met2: FL1 = ', FL1) End;
Var VI:ObjName1; { - переменная объектного типа - предка }
V2 : ObjName2; { - " " " потомка }
{--------- - Основная программа }
Begin ClrScr;
Assign (Output, 'Inovirt.res'); Rewrite (Output);
Writeln ( 'ОБЪЕКТЫ, СТАТИЧЕСКИЕ МЕТОДЫ1 );
Writeln ('Работаем с VI - экземпляром типа предка');
VI.Met1; {- вызывается метод Met1 для экземпляра VI - предка }
{ Met1 вызывает метод ObjName1.Met2 - предка }
V1.Met2; { - непосредственно вызывается метод ObjName1.Met2; }
Writeln ('Работаем с V2 - экземпляром типа потомка');
V2.Met1; { - вызывается метод Met1 для экземпляра V2 - потомка; Met1 вызывает метод ObjName1.Met2 - предка, а не ObjName2.Met2 - потомка - в этом - ограничение }
V2.Met2 { - непосредственно вызывается метод ObjName2.Met2; }
Close (Output);
End.
Рис. 2
Схема ограничения вызова переопределенных статических методов