Книга: Описание языка PascalABC.NET

Виртуальные методы и полиморфизм

Виртуальные методы и полиморфизм

Полиморфизм (от греч. много форм) - это свойство классов, связанных наследованием, иметь различную реализацию входящих в них методов, и способность переменной базового класса вызывать методы того класса, объект которого содержится в этой переменной в момент вызова метода.

Полиморфизм используется в ситуации, когда для группы взаимосвязанных объектов требуется выполнить единое действие, но каждый из этих объектов должен выполнить указанное действие по-своему (т.е. у действия возникает много форм). Для этого определяется базовый для всех объектов класс с виртуальными методами, предусмотренными для меняющегося поведения, после чего эти методы переопределяется в потомках.

Для пояснения рассмотрим переопределение метода в подклассе:

type

Base = class

public

procedure Print;

begin

writeln('Base');

end;

end;

Derived = class(Base)

public

procedure Print;

begin

writeln('Derived');

end;

end;

Присвоим переменной базового класса Base объект производного класса Derived и вызовем метод Print.

var b: Base := new Derived;

b.Print;

Какая версия метода Print вызывается - класса Base или класса Derived? В данном случае решение будет принято еще на этапе компиляции: вызовется метод Print класса Base, заявленного при описании переменной b. Говорят, что имеет место раннее связывание имени метода с его телом. Если же решение о том, какой метод вызывать, принимается на этапе выполнения программы в зависимости от реального типа объекта, на который ссылается переменная b, то в данном случае вызывается метод Derived.Print (говорят также, что имеет место позднее связывание). Методы, для которых реализуется позднее связывание, называются виртуальными, а переменная базового класса, через которую осуществляется вызов виртуального метода, - полиморфной переменной. Таким образом, полиморфизм реализуется вызовом виртуальных функций через переменную базового класса. Тип класса, который хранится в данной переменной на этапе выполнения, называется динамическим типом этой переменной.

Для того чтобы сделать метод виртуальным, следует в объявлении этого метода после заголовка указать ключевое слово virtual с последующей ;. Для переопределения виртуального метода следует использовать ключевое слово override:

type

Base = class

public

procedure Print; virtual;

begin

writeln('Base');

end;

end;

Derived = class(Base)

public

procedure Print; override;

begin

writeln('Derived');

end;

end;

Теперь в аналогичном участке кода.

var b: Base := new Derived;

b.Print;

вызывается метод Print класса Derived за счет того что решение о вызове метода откладывается на этап выполнения программы.

Говорят, что методы Print завязаны в цепочку виртуальности. Чтобы разорвать ее (не вызывать методы в подклассах виртуально) используется ключевое слово reintroduce:

type

DerivedTwice1 = class(Derived)

public

procedure Print; reintroduce;

begin

writeln('DerivedTwice1');

end;

end;

Если мы хотим начать новую цепочку виртуальности, то следует использовать и virtual и reintroduce:

type

DerivedTwice2 = class(Derived)

public

procedure Print; virtual;reintroduce;

begin

writeln('DerivedTwice2');

end;

end;

Если переопределить виртуальную функцию невиртуальной без ключевого слова reintroduce, то ошибки не произойдет - будет выведено лишь предупреждение о том, что цепочка виртуальности нарушена. Таким образом, ключевое слово reintroduce в этой ситуации лишь подавляет вывод предупреждения.

При переопределении виртуального метода в подклассе его уровень доступа должен быть не ниже, чем в базовом классе. Например, public виртуальный метод не может быть переопределен в подклассе private-методом.

Оглавление книги


Генерация: 0.280. Запросов К БД/Cache: 4 / 1
поделиться
Вверх Вниз