Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Виртуальные методы. Конструкторы




Виртуальный (кажущийся, гипотетический) метод имеет спецификатор (стандартную директиву) Virtual. Например:

Procedure Met2; Virtual;

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

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

В соответствии с этим основные отличия переопределения виртуальных методов от переопределения статических методов состоят в следующем:

1) если для экземпляра потомка методы предка вызывают другие виртуальные
методы, имена которых есть в объекте-предке и в объекте-потомке, то вы­
зываются методы потомка;

2) виртуальные методы используют позднее связывание данных с методами,
с помощью которых они будут обрабатываться, т. е. связывание на этапе
выполнения программы.

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

Связывание каждого экземпляра объекта и его ТВМ осуществляется с по­мощью конструктора на этапе выполнения программы. Это специальный ме­тод, подобный обычной процедуре, но в заголовке вместо PROCEDURE стоит слово CONSTRUCTOR. Если объектный тип содержит виртуальный метод, то он должен содержать хотя бы один конструктор. Каждый экземпляр объекта должен инициализироваться отдельным вызовом конструктора. Конструктор инициализирует экземпляр объекта и устанавливает для него значение адреса его ТВМ. Экземпляр объекта содержит только адрес ТВМ, а не саму ТВМ.

Вызов конструктора должен предшествовать вызову любого виртуального метода для обработки данного экземпляра объекта. Обращение к виртуально­му методу до вызова конструктора вызовет ошибку на этапе выполнения про­граммы, так как нет связи экземпляра объекта с его ТВМ.

При отладке программы можно использовать директиву компилятора {$R+}. При этом компилятор будет проверять, инициализирован ли экземп­ляр объекта, вызывающий виртуальный метод. Если в процессе проверки инициализации экземпляра объекта, вызывающего виртуальный метод, будет обнаружен вызов метода до инициализации объекта конструктором, выдается сообщение о фатальной ошибке 210:

Object not initialized - объект не инициализирован.

Так как директива {$R+} замедляет выполнение программы, после отлад­ки директиву надо удалить; по умолчанию работает директива {$R->.

В объекте может быть сколько угодно конструкторов. Конструктор не мо­жет быть виртуальным. Конструктор может быть только статическим и может быть переопределен. Конструкторы наследуются так же, как и другие стати­ческие методы. Из конструктора можно вызывать и виртуальные методы.

Метод конструктора может быть и пустым, так как основная информация содержится не в теле конструктора, а связана с его заголовком, содержащим слово Constructor. Например:

Constructor TA.TNIT ;

Begin

End;

Конструктору принято давать имя INIT. На практике в качестве конструк­тора используют метод, который устанавливает некоторые начальные значения экземпляра объекта. В конструкторе может происходить выделение ОП из ку­чи, если поля данных динамические, и необходимая инициализация полей дан­ных (в том числе и вызовы конструкторов-предков для унаследованных полей).

Пример программы с использованием виртуальных методов дан в листинге 4. Это вариант программы листинга 3, но с виртуальным методом Met2.

Листинг 4.Использование виртуальных методов.

Program virt1; {$F+,R+}    Uses Crt;

Type ObjName1 = object   { - объявление объекта-предка } Fl1 : integer;

Constructor Met1; { - конструктор }

Procedure Met2; Virtual; { - виртуальный метод } End; ObjName2 = object(ObjName1){- объявление потомка}

Procedure Met2; Virtual; { - виртуальный метод } End;

{ --   Методы объекта ObjName1 ------  }

Constructor ObjName1.Met1; Begin Fl1 := 12;

Met2; { - вызов Met2 из конструктора }

End;

Procedure ObjNamel.Met2;

Begin

Writeln ( 'Работает метод ObjName1.Met2: FL1 = ', Fl1) End;

{ --   Методы объекта ObjName2 ------  }

Procedure ObjName2.Met2; Begin Fl1 := 34;

Writeln ( 'Работает метод ObjName2.Met2: FL1 = ', Fl1) End;

Var VI:ObjName1;{- переменная объектного типа - предка }
V2 : ObjName2; { - " " " потомка }

{ ------ Основная программа ---------- }

Begin  ClrScr;

Assign (Output, '2virt.res'); Rewrite (Output);

Writeln ( 'ОБЪЕКТЫ, ВИРТУАЛЬНЫЕ МЕТОДЫ' );

Writeln ('Работаем с VI - экземпляром типа предка'); VI.Met1; { - вызывается конструктор Met1 для экземпляра VI - предка }

{ Met1 вызывает метод ObjName1.Met2 - предка }

VI.Met2; { - непосредственно вызывается метод ObjName1.Met2; }

Writeln ('Работаем с V2 - экземпляром типа потомка'); V2.Met1; { - вызывается конструктор Met1 для экземпляра V2 - потомка VI; Met1 вызывает метод ObjName2.Met2 - потомка -в этом достоинство виртуальных методов }

V2.Met2 { - непосредственно вызывается метод ObjName2.Met2; }

Close. (Output) ;

End.

Каждый экземпляр объекта должен инициализироваться отдельным вызо­вом конструктора. Нельзя инициализировать один экземпляр объекта и затем присваивать этот экземпляр другим, неинициализированным объектам. Дру­гие экземпляры, даже если они содержат правильные данные, не будут ини­циализированы оператором присваивания и заблокируют систему при любых вызовах их виртуальных методов. Например:

Var Obj1, Obj2 : TObj; { - объявление переменных } Begin

Obj1.Init; { - инициализация Obj1 }

Obj2 := Obj1; { - недопустимо до инициализации Obj2

с помощью Obj2.Init; }

End.

Хорошим стилем ООП является использование процедур инициализации предков. То есть если потомок имеет новую процедуру инициализации, то в ней обычно сначала вызывается процедура инициализации (например, конст­руктор) непосредственного предка, а затем выполняется своя. Это естествен­ный способ проинициализировать наследуемые поля предназначенным для этого методом.

Дополнительная возможность вызова метода, непосредственно наследуемо­го объектом-потомком, - использование ключевого слова Inherited (насле­дуемый) перед именем вызываемого метода. Например, Objl непосредствен­ный предок объекта Obj2. В состав Objl входит метод Metl. Вызов этого метода объекта Objl из метода Obj2.Met2 может быть задан явно в виде:

Procedure Obj2.Met2;

Begin Inherited Met1 (A1, A2);

{ Это эквивалентно вызову: Obj1.Met1 (A1, A2); }

End;

При этом не надо знать имя объекта-предка (Objl). Основные правила использования виртуальных методов:

1) если тип объекта-предка описывает метод как виртуальный, то все его по­томки, которые реализуют свой метод с тем же именем, должны описать
этот метод как виртуальный. Нельзя виртуальный метод заменить статическим. Иначе компилятор выдаст сообщение об ошибке:

Error 149: VIRTUAL expected - ОЖИДАЕТСЯ СЛОВО VIRTUAL.

2) если переопределяется виртуальный метод, то заголовок переопределяемо­
го метода не может быть изменен; должны остаться неизменными: количество, последовательность и типы формальных параметров в одноименных
виртуальных методах. Если этот метод - функция, то не должен изменяться и тип результата. При нарушении этого правила компилятор выдаст сообщение:

131: Header does not match previous definition - заголовок не соответствует предыдущему определению;

3) в описании объекта, имеющего виртуальные методы, обязателен -конструктор. Он устанавливает работу механизма виртуальных методов. Вызов виртуального метода без предварительного вызова конструктора может при­
вести к тупиковому состоянию. Чтобы избежать этого, на период отладки
надо включить директиву компилятора {$R+};

4) каждый экземпляр объекта должен инициализироваться отдельным вызо­вом конструктора;

5) количество конструкторов может быть любым;

6) конструктор должен быть статическим и может быть переопределен.











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

В Паскале имеется дополнительный класс методов позднего связывания -динамические методы. Они являются подклассом виртуальных методов и от­личаются от них только способом вызова на этапе выполнения.

Объявление динамического метода аналогично виртуальному, за исключе­нием того, что оно должно включать индекс (номер) динамического метода, который указывается сразу за ключевым словом Virtual. Индекс динамиче­ского метода должен быть целочисленной константой в диапазоне от 1 до 65535 и представлять собой уникальное значение среди индексов других ди­намических методов данного объектного типа и его предков. Например:

Function GetSum: Real; Virtual 10;   где - 10 - ИНДЕКС.

Переопределение динамического метода аналогично переопределению вир­туального. Оно должно включать слово Virtual, за которым следует тот же индекс, что и в переопределяемом динамическом методе предка.

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

При использовании динамических методов создается таблица динамиче­ских методов (ТДМ, DMT - Dynamic Method Table), альтернативная табли­це виртуальных методов. В ней указываются только те виртуальные методы, которые переопределяются. Это экономит ОП, но требуется время для поиска в DMT объектов-предков. Поэтому производительность DMT ниже, чем VMT, так как доступ к методу через VMT - простое извлечение адреса из таблицы, а доступ к методу через DMT может привести к более длительному поиску.

Выбор типа метода

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

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

Преимуществом использования виртуальных методов является то, что ти­пы объектов и методы можно определить в модуле и поставить пользователю модуль в виде TPU-файла. Для работы с объектами модуля надо знать содер­жимое только интерфейсной части модуля. Используя полиморфные объекты и виртуальные методы, пользователь TPU-файла может добавлять новые мето­ды к уже существующим.

Добавление новых функциональных характеристик в программу без моди­фикации ее исходного кода (текста) называют способностью к расширению. Это - результат наследования. Позднее связывание позволяет связать новые методы с существующими во время выполнения программы, требуя лишь не­большого увеличения ТВМ.

Не следует сомневаться в том, включать или не включать в объект метод, который может быть использован или не использован в конкретной програм­ме. Неиспользуемые методы не влияют ни на быстродействие программы, ни на размер ЕХЕ-файла: если они не используются, то они не включаются в него.

В общем случае рекомендуется делать методы виртуальными. Но они тре­буют ОП для ТВМ. Кроме того, каждый вызов виртуального метода проходит через ТВМ и требует для этого дополнительное время. Использование стати­ческих методов имеет смысл, если надо получить оптимальную эффектив­ность программы по скорости ее выполнения и использованию ОП. Статиче­ские методы вызываются непосредственно. Поэтому вызов статического мето­да более быстрый, чем вызов виртуального. Если в объекте нет виртуальных методов, в сегменте данных отсутствует ТВМ и программа будет работать бы­стрее. Однако в этом случае теряется вариант расширения возможностей на этапе выполнения программы, при позднем связывании.

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

Основные понятия

По способам размещения экземпляров объектов в ОП они могут быть, как и другие переменные, статическими или динамическими.

Все приведенные до сих пор объекты были статическими. Они были объ­явлены в разделе VAR, имели имена и размещались в сегменте данных или в стеке (локальные объекты). ОП для них выделялась до начала выполнения программы. Так же как и любые типы данных в Паскале, объекты могут быть динамическими и размещаться в куче. Работа с динамическим объектом ана­логична работе с динамической переменной: надо объявить указатель на объ­ект, создать динамический объект (с выделением ему ОП), обработать и уда­лить (с освобождением выделенной ОП).

После создания динамических объектов с помощью процедуры или функ­ции New значения указателей и динамических переменных можно использо­вать, например, в операторах присваивания:

PObjl := PObj2; - копирование указателя на объект;

Pobjl^ := PObj2^; - копирование полей динамического объекта.










Последнее изменение этой страницы: 2018-05-10; просмотров: 178.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...