Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
oaip_2 / Курсовая ОАиП.doc
Скачиваний:
95
Добавлен:
27.05.2013
Размер:
204.8 Кб
Скачать

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

Пусть заданы следующие объекты:

объект – сотрудники:

Type

TStaff = object

Name : String[30];

Money : Real;

Function GetSum : Real;

end;

объект – студент:

Type

TStudent = object (TStaff)

Ball : Real;{средний балл}

end;

Рассмотрим процедуру ShowSum которая выводит размер выплаты денежных средств:

для типа TStudent она имеет вид:

procedure TStudent.ShowSum;

begin

writeln(GetSum);

end;

где GetSum – некая функция возвращающая размер денежных выплат.

Для типа TStaff имеем:

procedure TStaff.ShowSum;

begin

writeln(GetSum);

end;

Видно, что обе процедуры схожи. Возникает вопрос: нет ли здесь логической ошибки?

Поскольку методы одинаковы , нет нужды помещать ShowSum в TStudent и TStaff. Т.к. TStudent автоматически наследуtт ShowSum от TStaff , поэтому нет необходимости переопределять этот метод. Но именно здесь и возникает ошибка, связанная со статическим методом.

Проблема заключается в следующем:

пока копия метода ShowSum не будет помещена в область действия TStudent для подавления метода ShowSum объекта TStaff , метод не бкдет работать правильно , если он будет вызываться из объекта типа TStudent . Если TStudent запускает метод ShowSum объекта TStaff , то и функция GetSum , используемая в методе, будет принадлежать объекту TStaff и стипендия будет расчитана неправильно, без учета среднего балла.

Это объясняется способом , которым компилятор осуществляет вызов методов.

Поскольку тим TStudent является потомком типа TStaff то сначала в сегмент кода будет скомпилирована функция TStaff.GetSum. Затем процедура TStaff.ShowSum вызывающая

TStaff.GetSum. Как и при вызове любой процедуры, компилятор замещает ссылки на TStaff.GetSum и TStaff.ShowSum в исходном коде на их адреса в сегменте кода. Т.о. при вызове код TStaff.ShowSum в свою очередь вызывает TStaff.GetSum, что исосавляет проблему. Фактически , наследуется следующая процедура:

procedure TStaff.ShowSum;

begin

writeln(TStaff.GetSum);

end;

Попросту говоря , метод объекта TStaff ничего не знает о существовании объекта TStudent . Т.о. метод ShowSum нельзя наследовать. Вместо этого он должен быть переопределен своей второй копией , вызывающей уже правильный метод.

Вызывая методы компилятор работает так:

сначала он ищет метод , имя которого внутри типа объекта. Тип TStudent определяет методы с именами GetSum, ShowSum. Если бы объект типа TStudent должен был вызывать один из этих методов, компилятор заменил бы его вызов на адрес одного из собственных методов TStudent.

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

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

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

Соседние файлы в папке oaip_2