Часто производные объектные типы на основе некоторого базового типа создаются другими программистами. Автор базового типа не может знать заранее, подойдут ли его реализации методов всем желающим. А вдруг кому-то понадобится моделировать не автомобиль с двигателем внутреннего сгорания, а трамвай, у которого тоже есть почти все свойства автомобиля, но процедура запуска двигателя совершенно другая?
В таком случае создатель базового метода может немного схитрить, облегчив работу и себе, и людям. Не нравится вам моя реализация метода "Начало движения" – пишите свою, пусть она перекроет то, что написал я.
Методы, которые можно перекрыть одноименными методами объектов-потомков, называются виртуальными(Рис. 6.2).
Рис. 10.2. Виртуальные методы.
Например:
TYPE Tcar=CLASS
PROCEDURE Move; VIRTUAL; { этот метод можно перекрыть }
END;
…
TYPE Ttruck=CLASS(Tcar)
PROCEDURE Move; OVERRIDE; { перекрытие метода Move }
END;
А вот в производном объекте для перекрытия одноименного виртуального метода нужно указать слово OVERRIDE (перекрыть). Тогда при выполнении следующего фрагмента программы:
VAR Car:Ttruck;
…
Car:=TTruck.Create;
Car.Move
будет вызван метод Move объекта Ttruck – в полном соответствии в принципом полиморфизма.
Бывают случаи, когда реализация одного и того же метода в базовом и производном объектном типах настолько различаются, что нет смысла расписывать реализацию метода базового типа. Достаточно указать, что у объекта может бытьметод с указанным именем.
Методы, не имеющие реализации, называются абстрактными. Поскольку абстрактный метод обязательно должен перекрываться настоящим (с реализацией) методом в объекте-потомке, все абстрактные методы должны одновременно быть и виртуальными. Записывается это так:
TYPE Tcar=CLASS
PROCEDURE Move;VIRTUAL;ABSTRACT;
END;
Реализации метода Tcar.Move в программе вообще нет. Соответственно, и вызвать на исполнение абстрактный метод в базовом объекте нельзя – исполнять-то нечего! Следующая запись вызовет ошибку:
VAR c:Tcar;
c:=TCar.Create;
c.Move
Особым случаем применения виртуальных методов следует считать их использование в конструкторе объекта. При создании любого объекта в Delphi, если родитель объекта явно не указан, он считается потомком некоего виртуального объектного типа Tobject. Следующие фрагменты программы эквивалентны:
TYPE TA=CLASS
и
TYPE TA=CLASS(TObject)
Если объект не требует какой-то специфической инициализации, то при создании переменной-объекта достаточно вызвать метод Create, унаследованный от объекта Tobject. Иначе обстоит дело при написании своего собственного конструктора. Рассмотрим пример:
TYPE TA=CLASS
a:BYTE;
CONSTRUCTOR Create;
END;
VAR aa:TA;
constructor TA.Create(x:byte);
begin
inherited Create;
self.a:=x
end;
В объекте TA создан метод-конструктор с именем Create, который перекрывает одноименный метод родительского объекта TObject. Однако именно метод родительского объекта вызывать следует обязательно: он выделяет память под объект. Поэтому в теле процедуры-конструктора оператором INHERITED сразу вызывается метод Create объекта-родителя. После выполнения родительского метода объект становится проинициализированным и можно задавать начальные значения его свойств.