Лекция 30.ppt
- Количество слайдов: 23
Конструктор. Деструктор. Виртуальные функции
При работе с объектами довольно типичной является ситуация, когда сложный метод приходится создавать заново для каждого типа объекта, хотя различия в поведении объектов могут быть небольшими. В этом случае обычно создается общий сложный метод, а различия вносятся в сменные подчиненные методы. Реализация такого подхода осуществляется с помощью виртуальных подчиненных методов. С этой целью после заголовка каждого сменного метода требуется написать Virtual. Procedure Метод(параметры); virtual; Если метод где то был объявлен виртуальным, то и все другие методы с тем же заголовком также должны быть объявлены виртуальными. Естественно, что у всех таких методов списки формальных параметров (и тип функции, если метод является подпрограммой функцией) должны быть эквивалентными.
Метод, использующий виртуальные методы, должен быть размещен в объекте, доступном всем объектам, где этот метод должен применяться. Основное отличие виртуальных методов заключается в том, что необходимые связи с ними в программе устанавливаются не на этапе компиляции и компоновки, а на этапе выполнения программы. С этой целью у объекта создаются таблицы виртуальных методов (ТВМ), куда записываются адреса всех используемых в этом объекте виртуальных методов. При выполнении программы в случае необходимости из этой таблицы выбирается адрес соответствующего варианта виртуального метода с целью использования именно этого варианта. Однако для использования такой таблицы предварительно ее следует заполнить этими адресами. Для этой цели применяются специальные методы, которые называются конструкторами (constructor).
Такой метод должен быть использован в программе до того, как будет обращение к виртуальному методу. Формальное отличие конструктора от обычного метода заключается в том, что вместо зарезервированного слова procedure используется зарезервированное слово constructor. Основное назначение конструктора — записать адрес виртуального метода в таблицу виртуальных методов, однако он может выполнять и другие действия по инициализации создаваемого объекта: задавать начальные условия, устанавливать необходимые связи, и т. д. Отсюда следует, что до вызова любого виртуального метода должен быть выполнен какой либо конструктор. Структура конструктора такая же, как и у любой процедуры, только вместо слова Procedure в заголовке метода пишется слово Constructor. constructor Init(параметры);
Если в объекте нет виртуальных методов, в нем может не быть ни одного конструктора, наобо рот, сли хотя бы один е метод описан как виртуальный, в состав объекта должен входить хотя бы один конструктор и обращение к конструктору должно предшествовать обращению к любому виртуальному методу. В паре с конструктором всегда существует и деструктор, роль которого противоположна роли конструктора, — он выполняет действия, завершающие работу с объектом: закрывает файлы, очищает динамическую память, осуществляет восстановление некоторых состояний, предшествующих работе с объектом и т. д. Следует иметь в виду, что в отличие от конструктора, осуществляющего настройку ТВМ, деструктор не связан с какими то специфичными действиями: для компилятора слова destructor и procedure — синонимы. В реальной практике ООП с деструкторами обычно связывают процедуры, которые не только прекращают работу с объектом, но и освобождают выделенную для него динамическую память.
Заголовок метода деструктора начинается со слова Destructor, в остальном же его структура такая же, как и у любого другого метода. destructor Done;
Скажем еще несколько слов о механизме раннего и позднего связывания. Раннее связывание предполагает, что связь между методами устанавливается во время трансляции программы (статические методы), в то время как позднее связывание предусматривает динамическую связь, т. е. реализуемую по мере необходимости в процессе выполнения программы. За счет такого механизма и удается правильно установить все нужные связи для виртуальных методов. Результат позднего связывания в этом случае зависит от типа того объекта, чей метод обратился к виртуальному методу. Конструктор для подготовки позднего связывания устанавливает связь между экземпляром объекта и таблицей виртуальных методов (ТВМ) объекта. Вызов виртуального метода делается не прямо, а через ТВМ: сначала по имени метода определяется его адрес, а затем по этому адресу передается управление. Именно по этим причинам использованию виртуальных методов должен предшествовать вызов конструктора.
Злоупотреблять виртуальными методами не следует, т. к. их использование увеличивает размер программы за счет таблиц виртуальных методов и уменьшает быстродействие, т. к. в этом случае при обращении к виртуальному методу сначала в таблице ищется его адрес, а затем уже происходит обращение к методу. Использование виртуальных методов в иерархии типов объектов имеет определенные ограничения: • если метод объявлен как виртуальный, то в типе потомка его нельзя перекрыть статическим методом; • объекты, имеющие виртуальные методы, инициализируются специальными процедурами которые называются constructor ; • списки переменных, типы функций в заголовках перекрывающих друга виртуальных процедур и функций должны совпадать полностью;
Пример: Требуется разработать программу, которая создает на экране ряд графических изображений (точки, окружность, линия, квадрат) и может перемещать эти изображения по экрану. Для перемещения изображений в программе будут использоваться клавиши управления курсором, клавиши <Ноmе>, <Еnd>, <Pg. Up>, <Рg. Dn> (для перемещения по диагональным направлениям) и клавиша <Tab> для выбора перемещаемого объекта. Для выхода из программы — клавиша <Esc>.
unit graphobj; Interface type TGraph. Obj=object x, y: integer; color: word; Constructor Init(ax, ay: integer; acolor: word); Procedure Draw(acolor: word); virtual; Procedure Show; Procedure Hide; Procedure Move. To(dx, dy: integer); end;
TPoint=object(Tgraph. Obj) Procedure Draw(acolor: word); virtual; end; TLine=object(TGraph. Obj) dx, dy: integer; Constructor Init(ax 1, ay 1, ax 2, ay 2: integer; acolor: word); Procedure Draw(acolor: word); virtual; end; TCircle=object(TGraph. Obj) r: integer; Constructor Init(ax, ay, ar: integer; acolor: word); Procedure Draw(acolor: word); virtual; end;
TRect=object(TLine) Procedure Draw(acolor: word); virtual; end; Implementation uses Graph, crt; Constructor TGraph. Obj. Init; begin x: =ax; y: =ay; color: =acolor; end; Procedure TGraph. Obj. Draw; begin end;
Procedure TGraph. Obj. Show; begin Draw(Color); end; Procedure TGraph. Obj. Hide; begin Draw(0); end; Procedure TGraph. Obj. Move. To; begin Hide; x: =x+dx; y: =y+dy; Show; end;
Procedure TPoint. Draw; begin Putpixel(x, y, color); end; Constructor TLine. Init; begin Inherited Init(ax 1, ay 1, acolor); dx: =ax 2 ax 1; dy: =ay 2 ay 1; end; Procedure TLine. Draw; begin Setcolor(color); line(x, y, x+dx, y+dy); end;
Constructor TCircle. Init; begin Inherited Init(ax, ay, acolor); r: =ar; end; Procedure TCircle. Draw; begin Setcolor(acolor); Circle(x, y, r); end; Procedure TRect. Draw; begin Setcolor(acolor); Rectangle(x, y, x+dx, y+dy); end; end.
Идею инкапсуляции полей и алгоритмов можно применить не только к графическим объектам, но и ко всей программе в целом. Ничто не мешает нам создать объект программу и "научить" его трем основным действиям: инициализации (init), выполнению основной работы (Run) и завершению (Done). На этапе инициализации экран переводится в графический режим работы, затем создаются и отображаются графические объекты (100 экземпляров TPoint и по одному экземпляру TLine, TCircle, TRect). На этапе Run осуществляется сканирование клавиатуры и перемещение графических объектов. На этапе Done экран переводится в текстовый режим и завершается работа всей программы.
unit Graph. App; Interface uses Graph. Obj; const NPoints=100; type TGraph. App=object Points: array[1. . NPoints] of TPoint; Line: TLine; Rect: TRect; Circ: TCircle; Active. Obj: integer; Constructor Init; Procedure Run; Procedure Show. All; Procedure Move. Active. Obj(dx, dy: integer); Destructor Done; end;
Implementation Uses graph; Constructor TGraph. App. Init; var d, r, k: integer; begin d: =detect; Initgraph(d, r, 'd: bpbgi'); randomize; for k: =1 to NPoints do Points[k]. init(random(getmax. X), random(getmax. Y), random(14)+1); Line. Init(Get. Max. X div 3, getmax. Y div 3, 2*getmax. X div 3, 2*getmax. Y div 3, 2); Circ. Init(Get. Max. X div 2, Get. Max. Y div 2, get. Max. Y div 5, 1); Rect. Init(2*Get. Max. X div 5, 2*getmax. Y div 5, 3*getmax. X div 5, 3*getmax. Y div 5, 7); show. All; Active. Obj: =1; end;
Procedure TGraph. App. Run; var Stop: boolean; const d=5; begin Stop: =False; repeat case readkey of #27: Stop: =True; #9: begin inc (Active. Obj); If Active. Obj>2 then Active. Obj: =1 end;
#0: case readkey of #71: Move. Active. Obj( d, d); #72: Move. Active. Obj(0, d); #73: Move. Active. Obj(d, d); #75: Move. Active. Obj( d, 0); #77: Move. Active. Obj(d, 0); #79: Move. Active. Obj( d, d); #80: Move. Active. Obj(0, d); #81: Move. Active. Obj(d, d); end; Show. All; until Stop end;
Destructor TGraph. App. Done; begin Close. Graph; end; Procedure Tgraph. App. show. All; var k: integer; begin for k: =1 to NPoints do Points[k]. show; Line. Show; Rect. show; Circ. Show; end;
Procedure TGraph. App. Move. Active. Obj; begin case Active. Obj of 1: Rect. Move. To(dx, dy); 2: Circ. Move. To(dx, dy); end; end. Program Graph_Object; uses Graph. App; var App: TGraph. App; begin App. Init; App. Run; App. Done; end.
ДОМАШНЕЕ ЗАДАНИЕ 1. Составить опорный конспект лекции по теме «Инициализация и разрушение объекта. Конструктор. Деструктор. Виртуальные функции» на основе презентации. 2. Turbo Pascal. Немнюгин С. А. СПб. : Питер, 2002, cтр. 363 366.
Лекция 30.ppt