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

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

Следовательно, надо каким-то образом дать знать компилятору, что эти методы будут обрабатываться по-другому. Для этого в С# существует ключевое слово 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 выбирается адрес метода, а затем управление передается этому методу. Таким образом, при использовании виртуальных методов из всех одноименных методов иерархии всегда выбирается тот, который соответствует фактическому типу вызвавшего его объекта.


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



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