Перекрытие методов

Рассмотрим класс для описания животных, способных издавать звуки:

type TPet = class

procedure Speak;

end;

procedure TPet.Speak;

begin

Beep; // ничего особенного – просто звуковой сигнал

end;

Потомки TPet – классы TDog и TCat – тоже способны «издавать звуки», но делают это по-своему. Ситуация является достаточно типичной при проектировании иерархии классов: наследник имеет такие же методы как и предок, но реализует их своим способом. ООП даёт возможность описать в классе-потомке метод с тем же именем, что и в классе-предке, но с собственной реализацией. Это называется перекрытие (замещение) методов:

type TDog = class(TPet)

procedure Speak; // перекрытие метода TPet.Speak

end;

TCat = class(TPet)

procedure Speak; // перекрытие метода TPet.Speak

end;

procedure TDog.Speak;

begin

writeln('Bow-wow')

end;

procedure TCat.Speak;

begin

writeln('Mew')

end;

При перекрытии методов их сигнатуры (то есть количество и тип параметров) могут различаться.

Если дочерний класс не перекрывает метод предка, а добавляет новый метод с тем же именем, необходимо воспользоваться директивой overload, чтобы явно указать на перегрузку. Естественно, такие методы должны различаться сигнатурой:

type TCatWithVolume = class(TCat)

// не перекрыли TCat.Speak, а добавили метод с параметром

procedure Speak(Volume: Integer);overload;

end;

Разберём вопрос о перекрытии полей класса. Классическое ООП не допускает подобного. Однако в Object Pascal дочерний класс может объявить поле с тем же именем, что и поле в родительском классе, но с другим типом. В этом случае методы в дочернем классе будут работать с новым полем, методы в родительском классе – со старым. На практике такая возможность практически не используется, так как способна основательно запутать и проектировщика, и пользователей класса.

Достаточно часто метод класса-потомка не заменяет действия в методе класса-предка, а дополняет их. Чтобы не дублировать код, в методе класса-потомка можно вызвать метод класса-предка. Для вызова перекрытых методов ближайшего класса-предка применяется конструкция inherited имя-метода-класса–предка. Если имя и параметры вызываемого у предка метода совпадают с именем и параметрами вызывающего метода, достаточно записать только ключевое слово inherited:

procedure TCat.Speak;

begin

inherited; // вызов TPet.Speak – звуковой сигнал

writeln('Mew')

end;

Если в непосредственном предке метод, вызываемый через inherited, отсутствует, компилятор проводит поиск такого метода по иерархии классов вплоть до корневого класса. Если метод не найден, никаких действий не предпринимается.

В иерархии классов работа конструктора класса-потомка, как правило, начинается с вызова конструктора класса-предка для корректной инициализации полей предка. Добавим конструктор в класс TEmployee (используется вариант класса TPerson с простым конструктором):

type TEmployee = class(TPerson)

public

...

constructor Create;

end;

constructor TEmployee.Create;

begin

inherited; // можно написать inherited Create

// fAge:= 1, fName:= 'Person'

fName:= 'Employee'

end;

Для деструкторов в иерархии классов действует правило, согласно которому вызов унаследованного деструктора происходит в конце работы класса-потомка.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: