Киберфак – бесплатно скачать презентации PowerPoint, лекции, рефераты, шпоры, курсовые cyberfac logo
cyberfac.ru
На главную | Регистрация | Вход
  Статьи  
Главная » Статьи » Информатика » Алгоритмизация и программирование

Полиморфизм. Виртуальные и динамические методы

Полезная статья? Пожалуйста, поставьте "+"
Алгоритмизация и программирование - Содержание
Рассмотрим следующий пример. Пусть имеется некое обобщенное поле для хранения данных - класс tFiled и три его потомка - для хранения строк, целых и вещественных чисел:

type
tFiled = class
function GetData:string; virtual; abctract;
end;

tStringFiled = class(tFiled)
fData:string;
function GetData: string; override;
end;

tIntegerFiled = class(tFiled)
fData:Integer;
function GetData: string; override;
end;

tExtendedFiled = class(tFiled)
fData:Extended;
function GetData: string; override;
end;

function tStringFiled.GetData: string;
Begin
Result:=fData;
End;

function tIntegerFiled.GetData: string;
Begin
Result:=IntToStr(fData);
End;

function tExtendedFiled.GetData: string;
Begin
Result:=FloatToStr(fData,ffFixed, 7, 2);
End;

function ShowData(aFiled:tFiled): string;
Begin
Form1.Label1.Caption:=aFiled.GetData;
End;

В этом примере классы содержат разнотипные поля данных fData, а также имеют унаследованный от tFiled виртуальный метод GetData, возвращающий данные в виде строки. Внешняя по отношению к ним процедура ShowData получает объект в виде параметра и показывает эту строку.

Согласно правилам контроля соответствия типов (typecasting) ObjectPascal, объекту, как указателю на экземпляр класса, может быть присвоен адрес экземпляра любого из дочерних типов. Это означает, что в предыдущем примере в процедуру ShowData можно передавать объекты классов tStringFiled, tIntegerFiled, tExtendedFiled и любого другого потомка tFiled.

Но какой (точнее, чей) метод GetData будет при этом вызван? Тот, который соответствует классу фактически переданного объекта. Этот принцип называется полиморфизмом.

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

Различие между виртуальными и динамическими методами заключается в особенности поиска адреса. Когда компилятор встречает обращение к виртуальному методу, он подставляет вместо прямого вызова по конкретному адресу код, который обращается к VMT и извлекает оттуда нужный адрес. Такая таблица есть для каждого класса. В ней хранятся адреса всех виртуальных методов класса, независимо от того, унаследованы ли они от предка или перекрыты в данном классе. Отсюда и достоинства и недостатки виртуальных методов: они вызываются сравнительно быстро, однако для хранения указателей на них в таблице VMT требуется большое количество памяти.

Динамические методы вызываются медленнее, но позволяют более экономно расходовать память. Каждому динамическому методу системой присваивается уникальный индекс. В таблице динамических методов класса хранятся индексы только тех методов только тех динамических методов, которые описаны в данном классе. При вызове динамического метода происходит поиск в этой таблице. В случае неудачи просматриваются DMT всех классов-предков в порядке их иерархии и, наконец, tObject, где имеется стандартный обработчик вызова динамических методов. Экономия памяти очевидна.

Для перекрытия и виртуальных и динамических методов служит директива override, с помощью которой (и только с ней!) можно переопределять оба этих типа методов.

type
tParentClass=class
fFirstFiled:Integer;
fSecondFiled:longInt;
procedure StaticMethod;
procedure VirtualMethod1; virtual;
procedure VirtualMethod2; virtual;
procedure DynamicMethod1; dynamic;
procedure DynamicMethod2; dynamic;
end;

tChildClass=class(tParentClass)
procedure StaticMethod;
procedure VirtualMethod1; override;
procedure DynamicMethod1; override;
end;

Первый метод класса tChildClass создается заново, два остальных перекрываются. Создадим объекты этих классов:

var Obj1: tParentClass;
Obj2: tChildClass;

Внутренняя структура этих объектов показана ниже. 

Первое поле каждого экземпляра каждого объекта содержит указатель на его класс. Класс, как структура состоит из двух частей. Начиная с адреса, на который ссылается указатель на класс, располагается таблица виртуальных методов. Она содержит адреса всех виртуальных методов класса, включая и унаследованные от предков. Перед таблицей виртуальных методов расположена специальная структура, содержащая дополнительную информацию. В ней содержатся данные, полностью характеризующие класс: имя, размер экземпляров, указатели на класс-предок и т.д. Одно из полей структуры содержит адрес таблицы динамических методов класса (DMT). Таблица имеет следующий формат: в начале - слово, содержащее количество элементов таблицы. Затем - слова, соответствующие индексам методов. Нумерация индексов начинается с –1 и идет по убывающей. После индексов идут собственно адреса динамических методов. Следует обратить внимание на то, что DMT объекта Obj1 состоит из двух элементов, Obj2 - из одного, соответствующего перекрытому методу DynamicMethod1. В случае вызова Obj2.DynamicMethod2 индекс не будет найден в DMT Obj2, и произойдет обращение к DMT Obj1. Именно так экономится память при использовании динамических методов.

Как указывалось выше, указатель на класс указывает на первый виртуальный метод. Служебные данные размещаются перед таблицей виртуальных методов, то есть с отрицательным смещением. Эти смещения описаны в модуле SYSTEM.PAS:

vmtSelfPtr = -76
vmtIntfTable = -72
vmtAutoTable = -68
vmtInitTable = -64
vmtTypeInfo = -60
vmtFiledTable = -56
vmtMethodTable = -52
vmtDynamicTable = -48
vmtClassName = -44
vmtInstanceSize = -40
vmtParent = -36
vmtSafeCallException = -32
vmtAfterConstruction = -28
vmtBeforeDestruction = -24
vmtDispatch = -20
vmtDefaultHandler = -16
vmtNewInstance = -12
vmtFreeInstance = -8
vmtDestroy = -4

Поля vmtDynamicTable, vmtDispatch и vmtDefaultHandler отвечают за вызов динамических методов. Поля vmtNewInstance, vmtFreeInstance и vmtDestroy содержат адреса методов создания и уничтожения экземпляров класса. Поля vmtIntfTable, vmtAutoTable, vmtSafeCallException введены для обеспечения совместимости с моделью объекта COM. Остальные поля доступны через методы объекта tObject. В Object Pascal эта информация играет важную роль и может использоваться программистом неявно. В языке определены два оператора - is и as, неявно обращающиеся к ней. Оператор is предназначен для проверки совместимости по присвоению экземпляра объекта с заданным классом. Выражение вида:

AnObject is tObjectType

Принимает значение True только если объект AnObject совместим по присвоению с классом tObjectType, то есть является объектом этого класса или его потомком.

Оператор as введен в язык специально для приведения объектных типов. С его помощью можно рассматривать экземпляр объекта как принадлежащий к другому совместимому типу:

with AObjectOfSomeType as tAnotherType do . . .

От стандартного способа приведения типов использование оператора as отличается наличием проверки на совместимость типов во время выполнения: попытка приведения к несовместимому типу приводит к возникновению исключительной ситуации eInvalidCast. После выполнения оператора as сам объект остается неизменным, но выполняются те его методы, которые соответствуют присваиваемому классу.

Вся информация, описывающая класс, создается и размещается в памяти на этапе компиляции. Доступ к информации вне методов этого класса можно получить, описав соответствующий указатель, называющийся указателем на класс или указателем на объектный тип (class reference). Он описывается при помощи зарезервированных слов class of. Например, указатель на класс tObject описан в модуле SYSTEM.PAS и называется tClass. Аналогичные указатели определены и для других важнейших классов: tComponentClass, tControlClass и т.д.

С указателем на класс тесно связано понятие методов класса. Такие методы можно вызывать и без создания экземпляра объекта - с указанием имени класса в котором они описаны. Перед описанием метода класса нужно поставить ключевое слово class.

Разумеется, методы класса не могут использовать значения, содержащиеся в полях класса: ведь экземпляра класса не существует!!! Методы класса служат для извлечения внутренней информации класса. Ниже перечислены методы класса tObject:

Метод и Описание

сlass function ClassName:ShortString
Возвращает имя класса

сlass function ClassNameIs(const Name:ShortString):Boolean
Принимает значение True, если имя класса равно заданному

сlass function ClassParent:tClass
Возвращает указатель на родительский класс

сlass function ClassInfo:pointer
Возвращает указатель на структуру с дополнительными данными об опубликованных методах и свойствах.

сlass function InstanceSize:Longint
Возвращает размер экземпляра класса

сlass function InheritsFrom (aClass: tClass):Boolean
Возвращает True, если данный класс наследует от заданного

сlass function MethodAddress(const Name:ShortString):Pointer
Возвращает адрес метода по его имени (только для опубликованных методов)

сlass function MethodName (Addres: pointer):ShortString
Возвращает имя метода по его адресу (только для опубликованных методов)

В Delphi в класс tObject добавлены еще два виртуальных метода - AfterConstruction и BeforeDestruction. Как следует из названия, они вызываются сразу после создания экземпляра объекта и непосредственно перед уничтожением.

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

Type
tFirstClass=class
E:extended;
procedure SetData(aValue: Extended); overload;
end;

tSecondClass=class(tFirstClass)
I:integer;
procedure SetData(aValue: Integer); overload;
end;

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

Для перегрузки виртуального метода используется зарезервированное слово reintroduce:

procedure SetData(aValue:string); reintrouce;overload;

На перегрузку методов накладывается ограничение: нельзя перегружать методы, находящиеся в области видимости published.

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

Procedure NeverCallMe; virtual; abstract;

Никакого кода абстрактный метод не содержит. Его вызов приведет к созданию исключительной ситуации eAbstractError.
Категория: Алгоритмизация и программирование | Добавил: Ni-Cd (10 Декабря 2011)
Просмотров: 2334 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
  Полезные материалы  

В нашем каталоге файлов можно найти много полезной информации. Также советуем заглянуть в каталог статей: в нем есть полезные статьи по темам: Экономика предприятия, Общая экономика, Финансы и Кредит, также Словарь терминов по экономике, Маркетинг, Бухучет и Мировая экономика
Также есть полезная страница Факультеты МИФИ, которая расскажет о том, какие есть в МИФИ факультеты.
Меню
 

Навигация
Высокоуровневые методы информатики и программирования [28]
Информатика и программирование [34]
Информационные системы в экономике [36]
Языки программирования и методы трансляции [15]
Алгоритмизация и программирование [61]
 

Поиск
 

Онлайн
Онлайн всего: 5
Гостей: 5
Пользователей: 0
 

Статистика


Рейтинг@Mail.ru

 


2007 - 2024 © Ni-Cd. All Rights Reserved