Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
56
Добавлен:
29.02.2016
Размер:
198.14 Кб
Скачать

5.2 Виртуальные методы

При раннем связывании программа, готовая для выполнения, представляет со­бой структуру, логика выполнения которой жестко определена. Если же тре­буется, чтобы решение о том, какой из одноименных методов разных объектов иерархии использовать, принималось в зависимости от конкретного объекта, для которого выполняется вызов, то заранее жестко связывать эти методы с осталь­ной частью кода нельзя.

Следовательно, надо каким-то образом дать знать компилятору, что эти методы будут обрабатываться по-другому. Для этого в С# существует ключевое слово virtual. Оно записывается в заголовке метода базового класса, например:

virtual public void Passport() . . .

Слово virtualв переводе с английского значит «фактический». Объявление ме­тода виртуальным означает, что все ссылки на этот метод будут разрешаться по факту его вызова, то есть не на стадии компиляции, а во время выполнения про­граммы. Этот механизм называетсяпоздним связыванием.

Для его реализации необходимо, чтобы адреса виртуальных методов хранились там, где ими можно будет в любой момент воспользоваться, поэтому компилятор формирует для этих методов таблицу виртуальных методов (Virtual Method Table, VMT). В нее записываются адреса виртуальных методов (в том числе унаследо­ванных) в порядке описания в классе. Для каждого класса создается одна таблица.

Каждый объект во время выполнения должен иметь доступ к VMT. Обеспечение этой связи нельзя поручить компилятору, так как она должна устанавливаться во время выполнения программы при создании объекта. Поэтому связь экземп­ляра объекта с VMT устанавливается с помощью Специального Кода, автомати­чески помещаемого компилятором в конструктор объекта.

Если в производном классе требуется переопределить виртуальный метод, ис­пользуется ключевое слово override,например:

override public void Passport() . . .

Переопределенный виртуальный метод должен обладать таким же набором па­раметров, как и одноименный метод базового класса. Это требование вполне ес­тественно, если учесть, что одноименные методы, относящиеся к разным клас­сам, могут вызываться из одной и той же точки программы.

Добавим в листинг 2 два волшебных слова virtual иoverrideв описания методовPassport, соответственно, базового и производного классов (листинг 3).

Листинг 3 Виртуальные методы

using System;

namespace ConsoleApplication1

{

class Monster

{

. . .

virtual public void Passport()

{

Console.WriteLine( "Monster {0} \t health = {1} ammo = {2}",

name, health, ammo );

}

. . .

}

class Daemon : Monster

{

override public void Passport()

{

Console.WriteLine(

"Daemon {0} \t health = {1} ammo = {2} brain = {3}",

Name, Health, Ammo, brain );

}

. . .

}

class Class1

{ static void Main()

{

const int n = 3;

Monster[] stado = new Monster[n];

stado[0] = new Monster( "Monia" );

stado[1] = new Monster( "Monk" );

stado[2] = new Daemon ( "Dimon", 3 );

foreach ( Monster elem in stado ) elem.Passport();

for ( int i = 0; i < n; ++i ) stado[i].Ammo = 0;

Console.WriteLine();

foreach ( Monster elem in stado ) elem.Passport();

}

}

}

Результат работы программы:

Monster Monia health - 100 ammo = 100

Monster Monk health = 100 ammo =100

Monster Dimon health = 100 ammo = 100 brain = 3

Monster Monia health = 100 ammo = 0

Monster Monk health = 100 ammo - 0

Monster Dimon health = 100 ammo = 0 brain = 3

Как видите, теперь в циклах 1 и 3 вызывается метод Passport,соответствующий типу объекта, помещенного в массив.

Виртуальные методы базового класса определяют интерфейс всей иерархии. Этот интерфейс может расширяться в потомках за счет добавления новых вир­туальных методов. Переопределять виртуальный метод в каждом из потомков не обязательно: если он выполняет устраивающие потомка действия, метод на­следуется.

Вызов виртуального метода выполняется так: из объекта берется адрес его таб­лицы VMT, из VMT выбирается адрес метода, а затем управление передается этому методу. Таким образом, при использовании виртуальных методов из всех одноименных методов иерархии всегда выбирается тот, который соответствует фактическому типу вызвавшего его объекта.

Вызов виртуального метода, в отличие от обычного, выполняется через дополни­тельный этап получения адреса метода из таблицы VMT, что несколько замедляет выполнение программы.

С помощью виртуальных методов реализуется один из основных принципов объ­ектно-ориентированного программирования полиморфизм. Это слово в пере­воде с греческого означает «много форм», что в данном случае означает «один вызовмного методов». Применение виртуальных методов обеспечивает гиб­кость и возможность расширения функциональности класса.

Виртуальные методы незаменимы и при передаче объектов в методы в качестве параметров. В параметрах метода описывается объект базового типа, а при вызо­ве в него передается объект производного класса. В этом случае виртуальные ме­тоды, вызываемые для объекта из метода, будут соответствовать типу аргумента, а не параметра.

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

Все сказанное о виртуальных методах относится также к свойствам и индексаторам.