Виртуальные и динамические методы, замещающие методы


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

Адреса этих методов определяются лишь во время выполнения программы из специальной таблицы. Такой поиск называют еще поздним связыванием (late binding). Решение о вызове конкретного метода решается в процессе выполнения программы, и решение основывается на данных, хранящихся в объекте, вызывающем метод.

Таким образом, появляется возможность реализовать различные варианты поведения объектов разных классов при вызове методов с одним именем. Это, по сути, определение полиморфизма.

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

Примечания:
• Для объявления метода виртуальным служит ключевое слово-директива Virtual, которое указывается в конце объявления заголовка метода после точки с запятой.

• Директива Virtual всегда вводит новый виртуальный метод, никак не связанный с любым другим одноименным методом, наследуемым классом. Переопределенный виртуальный метод ведет себя аналогично переопределенному статическому методу, т.е. полиморфизм не проявляется. Переопределить виртуальный метод в потомке можно и статическим методом.

Type T1=Class
Procedure Test; Virtual; End;
T2=Class(T1)
Procedure Test; // Test скрывается, но не замещается
End;
Var SomeObject: T1;
Begin
SomeObject:=T2.Create;
SomeObject.Test; // Вызывается T1.Test

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

TParentClass(Obj). <метод>;

Динамические методы

Динамические методы вызываются медленнее виртуальных, но позволяют более экономно расходовать память. Каждому динамическому методу присваивается индекс — отрицательное число. В таблице динамических методов (Dynamic Method Table, DMT) класса хранятся индексы и адреса только тех динамических методов, которые описаны в данном классе. Если в DMT данного класса адрес нужного динамического метода не находится, то просматривается DMT класса-предка, и так далее по всей цепочке наследования до класса TObject. Таким образом, доступ к методу через DMT может привести к активному поиску в DMT разных классов и потребовать сотен тактов процессора.

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

Динамические методы используются для редко вызываемых методов, когда потерями в производительности можно пренебречь. Синтаксис объявления динамических методов:

Procedure <имя метода>[(<параметры>)}; Dynamic;
Function <имя метода>[(<параметры>)}: <тип результата>; Dynamic;

Редко перекрываемые методы рекомендуется делать динамическими.

Замещающие методы

В то время как, директивы Virtual и Dynamic всегда вводят новое имя метода, то директива Override всегда указывает на новую реализацию уже существующего наследуемого виртуального или динамического метода. Весь смысл виртуальных и динамических методов состоит в том, чтобы дать классу-потомку возможность модифицировать поведение метода, введенного в его классе-предшественнике. Директива Override служит для того, чтобы дать понять транслятору, что ваша цель — модифицировать (заменить или расширить — два разных варианта) реализацию наследуемого метода.

Объявление Override-метода должно в точности совпадать с объявлением исходного Virtual или Dynamic метода по названию, числу, именам и типам параметров, а также типу результата для функции. Новая строка в VMT (DMT) таблице не создается, поскольку адрес замещенного метода записывается в строку таблицы замещаемого метода. Таким образом, у класса-предка и класса-потомка адрес одноименного метода находится в строке таблицы VMT (DMT) с одинаковым смещением от ее начала. Однако «начинка» этих методов различна.

Синтаксис объявления замещающих виртуальных методов:

Procedure|Constructor|Destructor <имя метода>[(<параметры>)];Override;
Function <имя метода>[{<параметры>)]: <тип результата>; Override;;

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


Комментарии запрещены.




Статистика