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

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

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

virtual public void Passport()...

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

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

override public void Passport()...

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

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

Листинг 8.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[l] = 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 Daemon Dimon health - 100 ammo = 100 brain = 3

Monster Monia health = 100 ammo = 0 Monster Monk health = 100 ammo ■ 0 Daemon Dimon health = 100 ammo = 0 brain = 3

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

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

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




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