constructor Init(aBearing: integer; const aName, aFam, aRank : string);
В новом конструкторе больше параметров, и работать он будет, в сравнении с предком, чуть иначе. Другими словами, в наследнике он переопределен. А если так, то где же волшебное слово VIRTUAL? Его здесь нет и не должно быть, поскольку конструктор виртуален по определению.
Теперь обратимся к процедуре распечатки Report. В наследнике она, кроме прочего, должна распечатать поле воинского звания, а значит, будет переопределена. Поэтому и объявлена виртуальной, причем и в наследнике TMilitary, и в его предке TPerson. Это необходимо, поскольку лишь виртуальный метод предка может быть виртуальным у наследника: виртуальность передается по наследству. С учетом всего сказанного, объявления типов TPerson и TMilitary теперь будут такими.
TPerson = object
mBearing : integer; { год рождения }
mName : string; { имя }
mFam : string; { фамилия }
constructor Init(aBearing: integer; const aName, aFam : string);
procedure Report; virtual ;
end;
TMilitary = object (TPerson)
mRank : string; { воинское звание }
constructor Init(aBearing: integer; const aName, aFam,
aRank : string);
procedure Report; virtual ;
end;
Подытожим все изменения. В предке TPerson процедура Report стала виртуальной. В наследнике TMilitary добавлено поле mRank, а также изменены два метода: конструктор и процедура Report.
«Отселение» в отдельный модуль
Настало время реализовать методы наследника. Но прежде, чем взяться за это, совершим одно полезное дельце – переместим объект-предок TPerson в отдельный модуль. Именно так поступают профессионалы, создавая библиотеки объектов. Порядок создания программного модуля подробно изложен в главе 59, вкратце я напомню основные шаги.
Итак, создайте новый файл, перенесите туда через буфер обмена объявление типа TPerson и реализацию его методов. Объявление объекта разместите в секции INTERFACE модуля, а реализацию – в секции IMPLEMENTATION. И не забудьте объявить виртуальной процедуру Report. Дайте модулю имя PERSON и сохраните под именем «PERSON.PAS». У вас получится файл, показанный ниже. В нём объявлен ещё один тип данных – указатель на объект PPerson, но к нему обратимся позже.
unit Person ; { Модуль, содержащий описание и реализацию объекта «ЧЕЛОВЕК» }
interface
type PPerson = ^TPerson ; { указатель на объект «ЧЕЛОВЕК» }
TPerson = object
mBearing : integer; { год рождения }
mName : string; { имя }
mFam : string; { фамилия }
constructor Init(aBearing: integer; const aName, aFam : string);
procedure Report; virtual ;
end;
implementation
{--- Реализация объекта «ЧЕЛОВЕК» ---}
constructor TPerson.Init(aBearing: integer; const aName, aFam : string);
begin
mBearing := aBearing;
mName := aName;
mFam := aFam;
end;
procedure TPerson.Report;
begin
Writeln(mBearing:6, 'Фамилия: '+mFam:20, ' Имя: '+mName);
end;
end.
Теперь то, что переехало в модуль Person, из первичного файла проекта удалим, и добавим в начале программы ссылку для импорта модуля.
USES Person;
Сохраните новую версию файла под именем «P_61_3» и убедитесь, что она компилируется без ошибок. Затем вставьте в первичный файл приведенное ранее объявление типа для наследника TMilitary. В итоге заготовка будущей программы станет такой.
{ P_61_3 – Демонстрация принципов наследования и полиморфизма }
uses Person ; { Объект TPerson импортируется из модуля Person }
type { объект «ВОЕННОСЛУЖАЩИЙ» }
TMilitary = object (TPerson)
mRank : string; { воинское звание }
constructor Init(aBearing: integer; const aName, aFam, aRank : string);
procedure Report; virtual ;
end;
begin
end.
Реализация методов
Отсюда приступим к реализации переопределенных методов нового объекта. Начнем с конструктора. Конечно, он мог бы повторить действия объекта-предка, но это неразумно. Ведь цель объектной технологии – упростить программирование, избежать повторов, не так ли? Избежать повтора здесь очень просто: внутри конструктора наследника вызовем конструктор предка, передав ему нужные параметры.
TPerson.Init(aBearing, aName, aFam);
Вызов конструктора предка содержит имя этого предка – префикс TPerson. Обращение потомка к методам предка – обычная практика. По этой причине в Паскале учреждено ключевое слово INHERITED – «унаследованный». Если предварить им вызов унаследованного метода, то префикс с именем предка станет излишним.
Читать дальше