Основы программирования (947332), страница 58
Текст из файла (страница 58)
С использованием полиморфизма реализуйте вращение этих фигур вокруг их геометрических центров с разными скоростями и различными направлениями вращения.Задание 2. Модифицируйте программу предыдущего задания, изменив закондвижения объектов, например, пусть каждый из них движется сверху вниз. Оценитеобъем исправлений в программе.Задание 3. Модифицируйте программу предыдущего задания, определив свойзакон движения каждого объекта.
Оцените объем исправлений в программе.11.7. Динамические полиморфные объекты. ДеструкторыBorland Pascal содержит специальные средства, предназначенные дляработы с динамическими полиморфными объектами и динамическими полями как динамических, так и статических объектов.Конструирование и уничтожение динамических полиморфных объектов. Для выделения памяти под динамические полиморфные объекты целесообразно использовать функцию New, которая позволяет указателю базо348//. Иерархии классоввого класса присвоить адрес объекта производного класса и при необходимости сразу вызвать конструктор создаваемого объекта.Функция New(<T\m указателя>[, <вызов конструктора>]) - возвращаетадрес размещенного и, возможно, сконструированного объекта.
Квадратныескобки означают, что второй параметр может быть опущен.При уничтожении полиморфных объектов необходимо учитывать наличие у него дополнительного поля, содержащего адрес ТВМ. Для корректного освобождения памяти следует предварительно вызвать специальный метод класса - деструктор. Деструктором может служить любой, в том числеи пустой метод класса, при описании которого служебное слово procedure заменено служебным словом destructor. Если деструктор переопределяется, тоего следует объявить виртуальным полиморфным, чтобы его вызов такжевыполнялся через ТВМ.Обычно деструктору присваивается имя Done.
Он может быть инициирован отдельным оператором или для его активизации можно использоватьспециальную форму процедуры освобождения памяти Dispose.Процедура /)/5/;(?5^С<указатель>[, <вызов деструктора>] ) - выполняетвызов деструктора, если он указан, и освобождает память.Пример 1L9. Разработать классы для реализации объекта «КомнатаД2», который должен отвечать на запрос о площади пола, и объекта «Трехмерная комната Д2», который должен отвечать на запрос о площади стен ипотолка. Предусмотреть возможность создания динамических объектовразработанных классов и хранения адреса объекта производного класса вполе указателя базового класса (2'й случай обязательного использованияслоэюного полиморфизма).Описание классов отличается от выполненных в программе примера11.7 тем, что для обоих классов объявляется деструктор.
Его придется объявить виртуальным полиморфным, так как возможен доступ через указательбазового класса к деструктору производного класса.Program ex;TypepTRoomD2=''TRoomD2;TRoomD2 ^objectlength, width:real;{поля: длина и ширина комнаты}function Square .real; virtual; {метод определения площади}constructor Init(lyW:real); {конструктор}destructor Done;{деструктор}end;Function TRoomD2.Square; {тело метода определения площади}BeginSquare:= length"^ width;End;349Часть 2. Объектно-ориентированное программированиеConstructor TRoomD2.Imt;{тело конструктора}Beginlength: =1;width: ^w;End;Destructor TRoomD2.Done;BeginEnd;Type pTVRoomD2^'' TVRoomD2;TVRoomD2 = object(TRoomD2)height:real;{дополнительное поле класса}function Square:real; virtual; {виртуальный полиморфныйметод}constructor Init(l, Wyh:real); {конструктор}end;Constructor TVRoomD2,Init;BeginшЛт/ей?/«//(7,w^; {инициализирует поля базового класса}height:^h;{инициализируем собственное поле класса}End;Function TVRoomD2.Square;BeginSquare: ^inherited Square+2*height*(length+ width);End;Var pA: pTRoomD2; pB:pTVRoomD2; {объявляем указатели}Begin{объект базового класса ~ указатель базового класса}pA:=New(pTRoomD2Jnit(3.5,5.1));{конструируем объект}ЖгИе1п('Площадь= \ pA\Square:6:2); {выведет «Площадь= 17.85»}Dispose(рА,Done);{уничтожаем объект}{объект производного класса - указатель производного класса}pB:=New(pTVRoomD2Jnit(3,5,5.I,2.7^^; {конструируем объект}WriteLn('nnouiadb=', pB\Square:6:2); {выведет «Площадь= 94.64»}Dispose(pB,Done);{уничтожаем объект}{проявление полиморфных свойств:объект производного класса - указатель базового класса}pA:=New(pTVRoomD2Jnit(3,5,5.1,2.7)^;{конструируем объект}WriteLnCIInoujadb'^ \ pA^,Square:6:2); {выведет «Площадь= 94.64»}Dispose(pA,Done);{уничтожаем объект}End.Динамические поля в статических и динамических полиморфныхобъектах.
Если при разработке классов для реализации полиморфных объек350//. Иерархии классовтов используют динамические поля (объTRoomDS0..1ектные или нет), то запрос памяти под нихlength, widthобычно помещают в конструктор, а освоSquare(), Init (), Done()бождение памяти - в деструктор. Тогда приуничтожении объекта автоматически освобождается память, отведенная для его поTBRoomDлей.-o! pBi^TRoomПри работе с динамическими объектаSquare(), Init(), Done()ми или с динамическими полями в статических объектах целесообразно использоватьсредства контроля выделения памяти, опи Рис.
11.20. Диаграмма классовсанные в параграфе 7.2.Возможна ситуация, когда в конструкторе запрашивается память подразмещение нескольких динамических полей, но реально удовлетворяетсятолько часть из них, например, только запрос памяти под размещение самого объекта. Естественно, такой объект в программе использоваться не может.В Borland Pascal существует специальный оператор fail, при выполнении которого все ранее удовлетворенные запросы на память аннулируются.
Приэтом, если объект динамический, то указателю присваивается значение nil, аесли объект статический, то конструктор, несмотря на то, что формально онявляется процедурой, возвращает значение false.Пример 11.10. Разработать класс для реализации объекта «Комната сбалконом Д», который должен реагировать на запрос об общей площади пола и о площади балкона. Предусмотреть возмоэ/сиость создания динамических и статических объектов, возмоэюность сохранения адреса объекта-потомка в указателе типа объекта-родителя и контроль выделения памяти.Для реализации объекта используем иерархию с наполнением(рис.
11.20). В качестве базового используем класс TRoomD3, аналогичныйTRoomD2, разработанному в предыдущем примере. Единственное отличиеэтого класса заключается в том, что его деструктор объявлен виртуальным,так как он переопределяется классом TBRoomD, который использует деструктор для освобождения памяти, выделенной под динамическое поле.Program ex;Type pTRoomD3=^TRoomD3;TRoomDS =objectlength, width:real;{поля: длина и ширина комнаты}function Square:real; virtual; {метод определения площади}constructor Init(l,w:real);{конструктор}destructor Done; virtual;{деструктор}end;351Часть 2. Объектно-ориентированное программированиеFunction TRoomDS,Square; {метод определения площади}BeginSquare:= length"^ width;End;Constructor TRoomDS.Init; {конструктор}Beginlength: ="1;width: =w;End;Destructor TRoomD3.Done;BeginEnd;Type pTBRoomD=^TBRoomD;TBRoomD=object(TRoomD3)pB:pTRoomD3;function Square:real; virtual;function BSquare:real; {площадь балкона}constructor Init(l,w:real; lb,wb:real);destructor Done;- virtual;end;Constructor TBRoomD.Init;Begininherited Init(l, w);if(lb^O)or(wb=OJ thenpB:=nilelsebeginNew(pB);ifpB=nil thenbeginWriteLnCHe хватает памяти для размещения поля *);Done; {завершение обработки; не нужно, если такойобработки нет и деструктор пустой}fail; {отменяет все выполненные заказы на память}endelse pB\Init(lb,wb);end;End;Function TBRoomD.BSquare;BeginifpBonil then BSquare:=pB\Squareelse BSquare:^0;End;352//.
Иерархии классовFunction TBRoomD, Square;BeginSquare: = inherited Square+BSquare;End;Destructor TBRoomD. Done;Begin {освобождаем память, выделенную под динамическое поле}ifpBonil then Dispose(рВ);End;Function HeapFuncfsize:Word):integer; far;Begin HeapFunc:=I; end;Var A: TBRoomD; pBLpTBRoomD; pB2:pTRoomD3;Begin {берем на себя обработку ошибок выделения памяти}НеарЕггог: =@HeapFunc;{статический объект с динамическим полем}if A.Init(3,2,5.1,2.5J) then {конструктор возвращает true или false}beginWriteLn(A.Square:6:2,A.BSquare:6:2); {выводим площади}A.Done; {вызываем деструктор как обычную процедуру}endelse WriieLn('He хватает памяти для размещения объекта, *);{динамический объект с динамическим полем - указатель типакласса-потомка}pBl:'=New(pTBRoomD,Init(3.2,5J,2.5,l));{nQw вернет адрес или nil}ifpBlonilthenbeginWriteLn(pBl\Square:6:2,pBl^.BSquare:6:2); {выводим площади}Dispose(pBl,Done);{уничтожаем объект}endelse writelnf'He хватает памяти для размещения объекта.