Function TMouse.IsVisible : Boolean; begin
... end;
...
End.
____________________________________________________________________________________________________________________________________________
Program Example;
Uses UMouse; {подключение модуля с классом}
Var Mouse : PMouse; Begin
...
End.
Билет 45. Объекты. Наследование.
НАСЛЕДОВАНИЕ
При наследовании объекты класса-потомка получают возможность использования ("наследуют") полей и методов класса-родителя, что позволяет повторно не определять эти компоненты класса.
Program NewMouseDemo;
Uses UMouse; { подключаем созданный ранее модуль }
Type
PNewMouse = ^TNewMouse;
TNewMouse = object(TMouse) {предок - TMouse} function GetClick(Var X,Y : Word) : Byte;
end;
Var
Mouse : PNewMouse; A,B : Word;
Button : Byte;
Function TNewMouse.GetClick(Var X,Y : Word): Byte;
begin | {функция возвращает номер нажатой |
... | кнопки в своем значении и текущие координаты мыши в параметрах- |
end; | переменных}; |
НАСЛЕДОВАНИЕ
Begin
New(Mouse,Init) ; if Mouse^.GetKeys > 0 then begin { проверка, подключена ли мышь }
Mouse^.On; repeat
Button := Mouse^.GetClick( A,B); if Button > 0 then
Writeln(Button,A,B) ; until Button = 3;
Mouse^.Off; end;
Dispose(Mouse,Done) ; End.
Новый класс TMouseNew унаследовал все свойства класса TMouse, т.к. является его потомком. Соответственно, класс TMouse для класса TMouseNew является предком, или родителем. В новом классе описан только один новый метод GetClick для получения информации о нажатой кнопке. При этом все методы класса TMouse становятся доступными для экземпляров класса TMouseNew.
Var M1 : PMouse; M2 : PNewMouse; ... M1 := M2 {допустимо}
Билет 46. Объекты. Простой полиморфизм .
В объектно-ориентированном программировании полиморфизм проявляется в возможности переопределять методы класса-предка, т.е. расширять свойства объекта путем "перестраивания" его методов.
Type
PPoint = ^TPoint; {объект – точка на экране}
TPoint = object X, Y : Word; Color : Byte;
constructor Init (InitX, InitY : Word;
InitColor : Byte);
destructor Done; procedure Draw;
end;
PCircle = ^TCircle; {объект - окружность на экране}
TCircle = object(TPoint) {производный от TPoint} Radius : Word; constructor Init (InitX,InitY,InitRadius:Word;
InitColor : Byte);
procedure Draw; end;
Сonstructor TPoint.Init; | {при создании объекта |
Begin | задаются координаты точки и |
X := InitX; | ее цвет через параметры |
Y := InitY; Color := InitColor; end; | конструктора} |
Destructor TPoint.Done; | { нет операторов, объект |
begin end; уничтожается с помощью Dispose}
Рrocedure TPoint.Draw; begin
Writeln('Рисуем точку x,y=',x,y,'Цвет=',Color) ; end;
Сonstructor TCircle.Init; begin
Radius := InitRadius;
TPoint.Init(InitX,InitY,InitColor) ; end;
Procedure TCircle.Draw; begin
Writeln('Рисуем окружность x,y,R=',x,y,Radius,
'Цвет=',Color);
end;
В программе описаны два класса: TCircle и его потомок TPoint. Деструктор Done наследуется, а методы Init и Draw на основе полиморфизма перекрываются.
В конструкторе класса TCircle не только инициализируется новое поле Radius, но и вызывается в явном виде конструктор "родителя". Это делается для того, чтобы проинициализировать те поля, которые "перешли по наследству" этому классу.
Метод Draw класса TCircle описан заново – рисование окружности отличается от рисования точки.
Приведенный пример относится к случаю простого полиморфизма, когда при вызове переопределенного метода тип объекта (класс), для которого вызывается данный метод, точно известен. При этом адреса методов-процедур, которые ассоциируются с именем Draw, и где размещаются команды этих методов, подставляются в вызовы данных методов на этапе компиляции. Такой процесс называется ранним связыванием– т.е. включением в машинный код точных адресов на те точки программы, с которых начинается размещение кода метода (такой метод называется статическим).
Var
Point : PPoint; Circle : PCircle;
Begin
... Point^.Draw; Circle^.Draw; ...
End.
Метод А |
Метод В |
Метод А |
Метод В |
Наследуется |
Переопределяется |
1. При вызове метода компилятор устанавливает тип объекта, вызывающего метод.
2. Установив тип, компилятор ищет метод в пределах типа объекта.
Найдя его, компилятор назначаетраннее связывание
вызов этого метода.позднее связывание
3. Если метод не найден, то компилятор начинает рассматривать тип непосредственного прародителя и ищет метод, имя которого вызвано, в пределах родительского типа. Если он найден, то вызов заменяется на вызов метода родителя. Если нет, то компилятор "поднимается" еще на один уровень и
т.д. При этом, если метод родителя вызывает другие методы, то последние также будут методами родителя, даже если потомки имеют свои собственные методы.
Билет 47. Объекты. Расписание и позднее связывание . Виртуальные методы.
Для стандартизации работы с объектами, имеющими полиморфные методы, введено понятие позднего связывания, когда компилятор формирует косвенное обращение к адресу ТВМ. Реальный адрес нужного метода не известен до момента выполнения программы. Этот метод подключается в процессе выполнения программы, когда однозначно определен тип объекта (класс).
Замещаемые (полиморфные) методы объектов, для которых необходимо реализовать механизм позднего связывания, называют виртуальнымии отмечают в описании объекта стандартной директивой virtual. Одни и те же виртуальные методы должны иметь одинаковые заголовки у всех объектов данной иерархии. Метод, объявленный виртуальным в некотором классе, обязан быть виртуальным и во всех его наследниках. Использование механизмов позднего связывания возможно как для статических, так и динамических объектов (размещенных в динамической памяти).
ТВМ Код
программы |
адрес 3 |
класса |
адрес 2 |
адрес 1 |
... |
адреса |
виртуальных |
методов |
адрес ТВМ |
поле 1 |
поле 2 |
... |
Динамический |
объект |
ВИРТУАЛЬНЫЕ МЕТОДЫ
Type
PPoint = ^TPoint;
TPoint = object X, Y : Word; Color : Byte;
constructor Init (InitX, InitY : Word;
InitColor : Byte);
destructor Done; procedure Draw; virtual;
end;
PCircle = ^TCircle;
TCircle = object(TPoint) Radius : Word; constructor Init (InitX,InitY,InitRadius:Word;
InitColor : Byte);
procedure Draw; virtual;
end; ...
{описания методов - прежние} ...
ТВМ |
класса |
TPoint |
X |
Y |
Color |
Адрес |
ТВМ |
... |
Draw |
ТВМ |
класса |
TCircle |
Y |
Circle^ |
Color |
Radius |
Адрес |
ТВМ |
... |
Draw |
X |
Var Point^
Point : PPoint;
Circle : PCircle;
P : array[1..2] of PPoint;
i : Byte;
Begin
New(Point,Init(…));
New(Circle,Init(…));
P[1] := Point; P[2] := Circle;
for i := 1 to 2 do P[I]^.Draw; End.
Тип обеих переменных Point и Circle – указатель, поэтому можно ввести массив указателей. Присваивание Р[2] := Circle корректно с точки зрения совместимости типов – все объекты-потомки совместимы со своими предками (обратное не верно).
Если бы метод Draw был статическим, то для рисования окружности потребовался бы, например, вызов: PСircle(P[2])^.Draw
Удобство использования виртуальных мето
дов становится более заметно при увеличении числа и усложнении иерархии объектов.
ПОСЛЕСЛОВИЕ
ИНФОРМАТИКА
(Основы программирования)
И Ф Н и Т
(первый курс, весенний семестр)
Лукша Олег Игоревич