Создание библиотек классов
Одним из достоинств ООП является возможность создания библиотек классов, на базе которых затем конструируют классы для реализации обьектов реальной задачи. Библиотечные классы при этом описывают в интерфейсной части модуля, а тела методов - в разделе реализации. Например:
Unit Room;
Interface
Type TRoom = object
length, width:real; {поля: длина и ширина комнаты}
finction Square: real; {метод определения площади}
procedure Init(l, w: real); {инициализирующий метод}
end;
Implementation
Function TRoom.Square; {метод определения площади}
Begin
Square:= length* width;
End;
Procedure TRoom.Init; {инициализирующий метод}
Begin
length:=l;
width:=w;
End;
End.
В этом случае основная программа будет подключать соответствующий модуль и работать с классом, его полями и методами, как с ресурсами библиотеки:
Program ex;
Uses Room; {подключаем модуль с описанием класса TRoom}
Var A:TRoom; {объявляем объект-переменную}
Begin
A.Init(3.5,5.1); {инициализируем поля объекта}
WriteLn('Комната: длина= ', A.length,
'; ширина ', A.width);
WriteLn('Площадь комнаты =', A.Square);
End.
В Borland Pascal можно ограничить доступ к полям и методам класса в пределах модуля.Для того описание класса делится на специальные секции:
public- секция, содержащая описание общих или общедоступных полей и методов класса;
private - секция, содержащая описание внутренних или скрытых полей и методов класса.
В описании класса три секции могут чередоваться, причем, если секции компонент не указаны, то по умолчанию принимается, что эти компоненты доступны как общие:
Unit <имя модуля>;
Interface
Туре <имя класса>= object
<описание общих полей и методов>
private
<описание внутренних полей и методов>
public
<описание общих полей и методов>
private
<описание внутренних полей и методов>
end;...
Например, в нашем случае, если обьекты класса TRoom используются только для получения информации о площади комнаты, то можно поля описать в секции private, но тогда доступ к этим полям из программы станет невозможным:
Unit RoomHiden;
Interface
Type TRoom = object
private {скрытые компоненты класса}
length, width; real; {поля: длина и ширина комнаты)
public {общие компоненты класса}
function Square:real; {метод определения площади}
procedure Init(l,w;real); {инициализирующий метод}
end;
Implementation
Function TRoom.Square; {метод определения площади}
Begin
Square:= length* width;
End;
Procedure TRoom.Init; {инициализирующий метод}
Begin
length:=l; width:=w;
End;
End.
Сокрытие некоторых полей и методов класса упрощает интерфейс класса, т. е. программист, использующий библиотечный класс, не получает лишней для него информации о внутренних механизмах реализации состояния и поведения обьектов данного класса. Одновременно с этим программист, занимающийся разработкой библиотечных классов, получает возможность вносить изменения в реализацию класса, не заботясь об изменении программ, использующих объекты данного класса.
Лекция 31. Наследование (2 яаса)
Наследование
Наследованием называют конструирование новых более сложных производных классов из уже имеющихся базовых посредством добавления полей и методов.
При наследовании объекты класса-потомка получают возможность использования («наследуют») поля и методы класса-родителя, что позволяет повторно не определять этих компонентов класса.
При описании класса-потомка указывают класс-родитель и дополнительные, определенные только для класса-потомка, поля и методы:
Туре <имя класса-потомка> = object(<имя класса – родителя>)
<описание дополнительных полей и методов класса>
end;...
Пример. Разработать класс для реализации объекта Трехмерная комната, который должен реагировать на запрос о площади и объеме комнаты.
В предыдущей задаче уже был определен класс TRoom в модуле Room, который содержал поля для хранения длины и ширины комнаты, метод инициализации полей и метод определения площади. Построим класс для реализации объекта Трехмерная комната на базе TRoom, добавив поле для хранения высоты комнаты и метод определения объема комнаты. Класс TRoom должен включать свой метод инициализации объектов.
Разрабатываемая пpoграмма должна содержать ссылку на использование модуля Room, в котором описан родительский класс TRoom:
Program ex;
Uses Room;
Type TVRoom = object(TRoom)
height:real; {поле для хранения высоты}
function V:real; {метод определения объема}
procedure NewInit(l,w,h:real); {инициализирующий метод}
end;
Procedure TVRoom.NewInit;
Begin
Init(l,w); {инициализируем наследуемые поля класса}
height:=h; {инициализируем собственное поле класса}
End;
Function TVRoom.V;
Begin
V:=Square*height; {обращаемся к методу базовот класса}
End;
Var A:TVRoom;
Begin
A.NewInit(3.4,5.1,2.8);
WriteLn('Площадь комнаты = ', A.Siquare:6:2);
WriteLn('Объем комнаты = ', A.V:6:2);
End.
Класс TVRoom, таким образом, включает три поля: length, width и height и четыре метода: Square, Init, NewInit и V. Все поля и методы доступны из методов производного класса и программы.
Если программа, работая с объектами класса-потомка, не использует некоторых методов родителя, то в исполняемую программу они не включаются.
Примечание. По правилам Borland Pascal у класса может быть только один родитель, но сколько угодно потомков. Поскольку кажлый произволный класс добавляет при наследовании свои поля и методы, в иерархии классов по мерс удаления от корня дерева иерархии сложность классов и соответственно объектов, которые эти классы реализуют, возрастает. Одновременно возрастает и специализация классов. Наиболее универсальные классы, таким образом, находятся у корня дерева классов.
Операция присваивания объектов родственных классов. В Borland Pascal допустимо присваивание объектам класса-родителя значений объектов класса-потомка. Обратное присваивание не разрешено, так как при его выполнении методом «поле за полем» собственные поля объекта класса-пoтомка окажутся не определенными. Например:
Var A:TRoom;
B:TVRoom;...
А:=В; {допустимо}
В:=А;... {недопустимо: ошибка!}
Особенности работы с указателями на объекты родственных классов. По правилам Borland Pascal допустимо указателям на объекты класса-родителя присваивать адреса абъектов класса-потомка. Однако при этом указатель на объект базового класса не обеспечивает возможности обращения к полям и методам, объявленным в производном классе.
Например:
Var pC:^TRoom; {указатель на объекты базового класса}
E:TVRoom;... {объект производного класса}
рС:=@Е; {присваиваем указателю на объекты базового класса
адрес объекта производного класса}
pC^.height:=2.7; {ошибки, указатель на объекты типа класса-родителя
не подозревает о существовании поля
height класса TVRoom}
В этих случаях приходится явно переопределять тип указателя, используя имя типа указателя:
Type pTVRoom=^TVRoom;
Var pC:^TRоот; {указатель на объекты базового класса)
E:TVRoom;... {объект производного класса}
рС:= @E; {присваиваем указателю на объекты базового класса
адрес объекта производного класса}
pTVRoom(pC)^.hei gh t:=2.7; {явно переопределяем тип указателя}
Композиция
Композицией называют способ конструирования классов, при котором в строящийся класс включают объекты других классов. Включение реализовано посредством использования объектных полей - полей типа «класс».
Пример. Разработать класс для реализации объекта Квартира, который должен реагировать на запрос о жилой площади квартиры.
Физически любая квартира состоит из нескольких комнат. Ранее у нас уже был разработан класс TRoom, который хранил данные о длине и ширине комнаты и «умел» реагировать на запрос о площади комнаты. Количество комнат в квартире сравнительно не велико и всегда ограничено, для определенности будем считать, что реализуемый объект не может включать более 15 комнат. Тогда разрабатываемый класс TFlat должен включать массив из 15 объектов типа TRoom. Реальное количество комнат будем хранить в поле n.
Для инициализации объектных полей будем передавать в инициализирующий метод специальный массив значении параметров. Поскольку размерность этого массива будет определяться реальным количеством комнат, а значит будет отличаться от размерности поля rooms, необходимо описать параметр как открытый массив или нетипизированный параметр. Используем второй вариант.
Program ex;
Uses Room; {модуль Room определен в предыдущих примерах}
Type TFlat =object {описание класса)
n:byte; {количество комнат}
rooms:array[1..15] of TRoom; {массив объектов TRoom}
function FlatSquure:real; {метод определения площади}
procedure Init(an:byte;Var arooms); {метод инициализации)
end;
Procedure TFlat.Init; {тело метода инициализации}
Var a:array[1..15] of TRoom absolute arooms; {переопределение типа
массива наложением}
i: byte;
Begin
п:=ап; {инициализируем поле количества комнат}
for i:=1 to n do {инициализируем объектные поля, вызывая метод
инициализации TRoom для каждой комнаты и передавая
ему размеры комнат)
rooms[i].Init(a[i].length, a[i].width);
End;
Function TFlat.FlatSquure; {тело метода определения площади}
VarS:real;
i:integer;
Begin
S:=0;
for i:=1 to n do {суммируем площади комнат}
S:=S+rooms[i].Square;
FlatSquare: =S;
End;
Const mas:array[1..3] of TRoom = ((length:2.5; width:3.75),
(length:2.85; width:4.1),
(length:2.3; width:2.8));
Var F:TFlat; {объявляем объект-переменную}
Begin
F.Init(3,mas); {инициализируем объект}
WriteLn('Площадь квартиры=', F.FlatSquare); {определяем площадь}
End.
Наполнение
Наполнением называют способ конструирования классов, при котором в строящийся класс включают неопределенное количество: от 0 до сравнительно больших значений (на практике обычно до нескольких десятков), объектов других классов.
Пример. Разработать класс для реализации объекта Комната с балконом, который должен реагировать на запрос об общей площади.
Балкон в комнате может существовать или нет. Для простоты будем считать, что в комнате может быть не более одного балкона прямоугольной формы. Следовательно, разрабатываемый класс можно наследовать от класса TRoom и включить в него указатель на объект класса TRoom. Он должен добавлять свои методы определения площади и инициализации объектов, учитывающие наличие или отсутствие балкона.
Program ex;
Uses Room;
Type
TBRoom =object( TRoom)
pB: ^TRoom;
function BSquare:real;
procedure InitAll(l,w:real; lb,wb:real);
end;
Procedure TBRoom.InitAll;
Begin
Init(l,w);
if (lb = 0)or(wb=0) then pB:=nil
else
begin
Nеw(pВ);
pB^.Init(lb,wb);
end;
End;
Function TBRoom.BSquare;
Begin
if pB=nil then BSquare:= Square;
else BSquare:= Square + pB^.Square;
End;
Var B:ТВRoom; {объявляем объект-переменную}
Begin
В.InitAll(3.4,5.1,1.8,0.8); {инициализируем объект}
WviteLn('Площадь комнаты с балконом=', B.BSquare);
End.
Процесс выделения памяти под динамические поля объекта необходимо контролировать. С этой целью используют средства контроля выделения памяти. Cуществуют специальные средсгва контроля выделения памяти под динамические поля, которые обычно используют при разработке конструкторов, эти средства и приемы их использования будут рассмотрены дальше.
Дата добавления: 2015-12-01; просмотров: 1040;