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 статических методов объектов, Класс С ( потомок С )связанных иерархически:

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

Удобство использования виртуальных мето

дов становится более заметно при увеличении числа и усложнении иерархии объектов.

ПОСЛЕСЛОВИЕ

ИНФОРМАТИКА

(Основы программирования)

И Ф Н и Т

(первый курс, весенний семестр)

Лукша Олег Игоревич

Наши рекомендации