Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Объектно-ориентированное программирование

..pdf
Скачиваний:
11
Добавлен:
12.11.2023
Размер:
16.61 Mб
Скачать

2.1. Определение класса

Для инициализации полей объектов можно использовать три способа:

-инициализировать поля в основной программ е операторами присваивания вида:

<имя объекта>.<имя поля> := <значение>

-разработать специальный метод инициализации, который получает список параметров и инициализирует ими поля (такой метод обычно называют Init);

-использовать типизированные константы вида:

Const <имя объекта> : <имя класса> =

(<имя поля 1> : <значение поля 1>; <имя поля 2> : <значение поля 2>;

<имя поля К>:<значение поля К>);

Способ инициализации полей объектов выбирают исходя из особенностей решаемых задач.

Пример 2.1. Описание класса (класс Окно). Пусть требуется описать класс, представляющий окно в текстовом режиме. Основным методом такого класса может быть процедура изображения окна, которая вызывает стандартные процедуры модуля Crt: Window, Textbackground и Clrscr. Целесообразно добавить два дополнительных метода, позволяющих определять размеры окна. В результате получим следующую программу:

Program WinOb; Uses Crt;

Type

{Описание структуры класса} Win = Object {класс Окно}

{Поля класса}

XI, Y1, {координаты верхнего левого угла окна}

Х2, Y2, {координаты нижнего правого угла окна} Cf: byte; {цвет фона}

{Методы класса}

Procedure Init(Xnl, YnlyXn2, Yn2,Cfn.'byte); {инициализация полей} Procedure MakeWin; {создание окна}

Function GetSizeX: byte; {определение размера окна по оси X} Function GetSizeY: byte; {определение размера окна по оси Y}

End;

{Описание методов класса}

Procedure Win.Init;

Begin Xl:=Xnl; Yl:=Ynl; X2:=Xn2; Y2:=Yn2; Cf:=CJh; End; Procedure Win.MakeWin;

61

 

 

2. Средства ООП в Borland Pascal 7.0

Begin

Window(Xl,Y1,X2,Y2); Textbackground(Cf)\ Clrscr End;

Function Win.GetSizeX;

 

Begin

GetSizeX: =X2-X1+1 End;

Function Win.GetSizeY;

 

Begin

GetSizeY:=Y2-Y1+1 End;

Var Winvar: Win; {объявление объекта}

Begin

 

 

with Winvar do {для объекта Winvar выполнить}

begin

 

Init(l,1,80,25,1);

{инициализировать поля объекта}

MakeWin;

{вызвать метод изображения окна}

Writeln(Cf ’ - ,GetSizeX, ’ - \GetSizeY); {вывести размеры окна} end;

Readkey;

End.

Врезультате работы программы на экране будет изображено синее окно,

вкоторое будут выведены три числа: код цвета фона и размеры окна (1 - 80 - 25).

Доступ к полям и методам класса осуществляется с помощью оператора присоединения with. Можно было бы использовать с той же целью составные имена:

Winvar.Init{l,1,80,25,1);

Winvar.MakeWin;

Writeln(Winvar.Cf, ’ , Winvar.GetSizeX, ’- \Winvar.GetSizeY);

Параметр Self. Параметр Selfявляется обобщенным именем экземпляра класса, которое неявно используется внутри методов для обращения к полям и методам. Компилятор автоматически обрабатывает данный параметр, поэтому явно его можно не указывать. Исключением является случай, когда какой-либо идентификатор текущего класса совпадает с внешним идентификатором, используемым в этом классе. Рассмотрим пример, в котором имеется необходимость в использовании параметра Self.

Type Rec = Record

{тип записи}

X, Y : word;

{поля данных записи}

end;

 

 

Pos =Object

{объявление класса}

X ,Y : word;

{поля данных класса}

Procedure lnit(P: Rec); {метод класса}

end;

Procedure Pos.Init; Begin

62

2.2. Наследование

with Р do {присоединить имя записи Р} begin

{Передать поля данных записи полям данных класса}

Self.X: = X; Self.Y:=Y; end

End;

Var R:Rec; P:Pos;

Begin R.X:=1; R.Y:=2; {инициализировать поля записи} P.lnit(R); {инициализировать объект}

Write{ РХ, ’ - \PY); {вывести значения полей объекта}

End.

2.2 . Наследование

В главе 1 сформулировано следующее определение: Наследование - это такое соотношение между классами, когда один класс использует структурную или функциональную часть одного или нескольких других классов (соответственно простое и множественное наследование).

ВBorland Pascal 7.0 реализовано простое наследование, при котором у класса может быть только один родитель, но сколь угодно потомков.

Любой класс можно объявить потомком ранее описанного класса. Потомок наследует все данные и методы класса родителя и дополняет их своими данными и методами.

Врезультате использования механизма наследование отпадает необходимость заново описыватьуже существующие в классе-родителе поля

иметоды. Требуется описать только те поля и методы, которых недостает в классе-родителе.

Доступ к полям, описанным в классе-родителе, осуществляется также как к собственным. Поиск метода в иерархии классов выполняется следующим образом.

1.В первую очередь компилятор устанавливает тип объекта.

2.Далее он ищет метод в классе объекта и если находит, то подключает

его.

3.Если метод в классе объекта не найден, то идет поиск в классе-родителе.

Вслучае успеха вызывается метод родителя.

4.Если метод в классе-родителе не найден, то поиск продолжается в классах-предках до тех пор, пока вызванный метод не будет найден.

Если компилятор не обнаруживает метод, то он фиксирует ошибку компиляции номер 44 {Fieldidentifier expected- «ожидается имя поля или метода

класса»).

Механизм наследования обеспечивает создание дерева родственных классов. Дерево может иметь несколько уровней и ветвей, где на каждом уровне добавляются необходимые поля и методы.

63

2. Средства ООП в Borland Pascal 7.0

Структура описания класса-потомка:

Туре <имя класса-потомка>=0^ес1(<имя класса-родителя>) <новые поля класса-потомка> <новые методы класса-потомка>

End;

Примеры 2.2 и 2.3 иллюстрируют преимущества механизма наследования.

П р и м ер 2.2. Р азр аб о тк а слож ного кл асса без и сп о л ьзо ван и я наследования (класс Символ). Пусть описан класс Символ (Symb), который позволяет создавать окно и выводить символ в заданную позицию.

Program SymbOb; Uses Crt;

Type

Symb = Object (класс Символ} (Поля класса}

XI, Y1, (координаты верхнего левого угла окна}

Х2, Y2, (координаты нижнего правого угла окна} CfCs, (цвет фона и символов}

Col,Line:byte; (позиция символа}

Sym.char; (символ} (Методы класса}

Procedure Init{Xnl, Ynl,Xn2, Yn2,CJh,Csn,Cl,Ln:byte;Sm:Char); Procedure Make Win; (создание окна}

Procedure Print;

(вывод символа}

End;

 

Procedure Symb.Init;

 

Begin

X2:=Xn2; Y2:=Yn2; Cf:=Cjh;

X l:—Xnl; Yl:=Ynl;

Cs:=Csn; Col:-Cl; Line:=Ln; Sym:=Sm;

End;

Procedure Symb.MakeWin;

Begin

Window(XI, Y1,X2,Y2); Textbackground(CJ); Clrscr

End;

Procedure Symb.Print;

Begin

TextColor(Cs); Gotoxy(Col,Line); Write(Sym)

End;

Var Symbvar: Symb; (объявление экземпляра класса}

Begin

Symbvar.Init(l,1,80,25,7,1,40,12, ’А ’); (инициализироватьобъект}

64

2.2. Наследование

Symbvar.MakeWin; {нарисовать окно}

Symbvar.Print; {вывести символ}

Readkey;

End.

Если сравнить примеры 2.1 и 2.2, то можно заметить, что поля X I, Y1, Х2, Y2, C f и метод MakeWin совпадают. Следовательно, класс Symb можно наследовать от класса Win.

Графически наследование классов можно изобразить в виде дерева иерархии родственных классов. При этом, в качестве комментария, могут быть указаны поля и методы классов.

Пример 2.3. Использование наследования (классы Окно и Символ).

На рис. 2.1 представлена иерархия классов для рассматриваемого примера, в которой показано, что класс Символ наследуется от класса Окно. Справа для классов указаны используемые поля и методы, причем для класса-потомка указаны только те поля и методы, которые отсутствуют в родительском классе. Иерархия классов в данном случае простая и имеет всего два уровня, где Win считается классом первого уровня, a Symb - классом второго уровня.

В рассматриваемом примере 2.3 класс Symb объявлен как потомок класса

Win

Program WinSymbOb;

Uses Crt;

{..................................................................................................} { Описание класса Win и его методов из примера 2 . 1 }

{..................................................................................................}

Туре

Symb - Object(Win) {класс-потомок «символ»}

{Новые поля}

С у, {цвет символов}

ColtLine:byte; {позиция символа}

Sym.char; {символ}

Поля: XI, Y1,X2, Y 2 - координаты окна Cfцвет фона

Методы: Init, MakeWin, GetSizeX, GetSizeY

Новые поля: Cs - цвет символов

Col, Line - позиция символа Sym - символ

Новые методы: Init, Print

Рис. 2.1. Иерархия классов примера 2.3

65

2. Средства ООП в Borland Pascal 7.0

{Новые методы}

Procedure Init(Xnl, Ynl,Xn2, Yn2,Cfh, Csn, Cl,Ln:byte;Sm:Char);

{инициализация полей}

Procedure Print; {вывод символа} End;

Procedure Symb.Init; Begin

Win.Init(Xnl,Ynl,Xn2, Yn2,Cfn); {используем родительский метод} Cs:=Csn; Col:=Cl; Line:-Ln; Sym: =Sm;

End;

Procedure Symb.Print;

Begin TextColor(Cs); Gotoxy(Col,Line); Write(Sym) End; Var Symbvar: Symb; {объявление экземпляра класса}

Begin

 

with Symbvar do begin

 

Init(l, 1,80,25,7,1,40,12, ’A ’);

{инициализировать объект}

MakeWin;

{изобразить окно}

Print

{вывести символ}

end;

 

Readkey;

 

End.

 

Результаты работы программы данного примера аналогичны результатам работы программы примера 2.2. Применение механизма наследования позволило повторно не описывать поля и методы ранее созданного класса, в результате чего заметно упростилась разработка класса Symb. Кроме этого, дополнительно появилась возможность использовать родительские методы GetSizeX и GetSizeY класса Win, также ранее определенные в классе Win.

Присваивание объектов. Для объектов возможно выполнение операции присваивания. Смысл данной операции заключается в том, что происходит поэлементное присваивание содержимого полей одного объекта полям другого. Данная операция применима как к объектам одного класса, так и к объектам классов одной иерархии. Причем разрешается только объектам родительских классов присваивать значения объектов производных классов. Присваивание в обратном порядке не допускается, так как, если в классе-потомке объявляются дополнительные поля, то при присваивании объекту класса-потомка значения объекта родительского класса эти дополнительны е поля остаю тся неопределенными.

Формат записи операции присваивания выглядит следующим образом:

<объект класса-родителя> := <объект класса-потомка>

Так для классов примера 2.3 возможно только присваивание полям объекта класса Win значений полей объекта класса Symb, например:

66

 

 

2.3. Полиморфизм

 

{......................................................................................................

 

 

}

{. . . Описание классов Win и Symb из примера 2 .3 ...........

}

{.......................................................................................................

Winvar: Win;

{объект-родитель}

}

Var

 

 

Symbvar: Symb; {объект-потомок}

 

Begin

Symbvar.Init(l,1,80,25,7,1,40,12, A );’ .

 

 

Winvar:= Symbvar;

{передать поля данных}

 

 

Winvar.MakeWin;

{изобразить окно}

 

Write(Winvar.CJ); {на сером фоне будет выведено синим цветом число 7}

End.

Операция присваивания применима и к динамическим объектам, память под которые запрашивается из динамической области, например

{......................

 

; • • • • ..................

................................ ...................

}

{ . . .

Описание классов Win и Symb из примера 2 .3 ..........

}

{........................................................................................................

 

Winvar: AWin;

 

}

Var

 

{указатель на объект-родитель}

 

 

Symbvar: ASymb;

{указатель на объект-потомок}

Begin

New(Symbvar);

{выделить память под объект}

 

 

Symbvar.Init(l, 1,80,25,7,1,40,12, А ’);, {инициализировать}

 

 

Winvar:= Symbvar;

{передать указатель}

 

 

 

WinvarЛ := SymbvarЛ;

{передать содержимое}

 

 

 

Winvar.MakeWin;

{изобразить окно}

 

 

 

Write(Winvar. Cfi;

{вывести символ}

 

End.

 

Dispose(Symvar);

{освободить память}

 

 

 

 

 

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

2.3. Полиморфизм

Borland Pascal реализует механизмы простого и сложного полиморфизма. Простой полиморфизм. М е х а н и з м п р о с т о г о п о л и м о р ­ ф и з м а обеспечивает возможность задания различных реализаций некоторого

единого по названию метода для классов различных уровней иерархии. Одноименные методы в этом случае называют с т а т и ч е с к и м и п о л и ­

мо р ф н ы м и .

ВООП считается, что все реализации одноименных методов иерархии образуют полиморфный метод семейства классов. Каждый вариант реализации при этом представляет собой отдельный аспект полиморфного метода семейства классов. Конкретный аспект статического полиморфного метода

67

2. Средства ООП в Borland Pascal 7.0

определяется типом объекта на этапе компиляции программы {раннее связывание).

Рассмотрим случай применения простого полиморфизма в языке Borland Pascal 7.0.

Пример 2.4. Применение простого полиморфизма. Пусть необходимо разработать программу, которая вы водит в окно не один символ, а последовательность одинаковых символов. Для построения нужного класса используем уже имеющиеся классы Win и Symb: наследуем класс Lot от класса Symb. При этом необходимо заменить метод Print, описанный в классе Symb (рис. 2.2). Для объектов класса Lot он будет выводить не один символ, а количество символов, заданное в поле N этого класса.

Program WinSymbLot;

Uses Crt;

{....................................................................................................................

}

(Описание класса Win и его наследника Symb из примера 2.3 ..

}

{....................................................................................................................

}

type

Lot = Object(Symb) (класс-потомок Lot}

N : Word', (новое поле - количество символов}

Procedure lnit(Xttl, Ynl,Xn2, Yn2,Cfh.Csn,Cl,Ln:Byte;Sm:Char; Nk:word);

(инициализация полей} Procedure Print; (переопределенный метод вывода символа}

End;

Procedure Lot.Init;

Begin

Symb.Init(Xnl,Ynl,Xn2, Yn2,CJh,Csn,Cl,Ln,Sm);

N : =Nk;

(инициализация нового поля}

End;

 

 

Поля: XI, Yl, X2, Y2 - координаты окна

 

Cf - цвет фона

 

Методы: Init, MakeWin, GetSizeX, GetSizeY

 

Поля: Cs - цвет символов

 

Col, Line - позиция символа

 

Sym —символ

 

Методы: Init, Print

 

Поля: N - количество символов

 

Методы: Init, Print - переопределен

 

Рис. 2.2. Иерархия классов примера 2.4

68

2.3. Полиморфизм

Procedure LotPrint; Var kbyte;

Begin

for i:=l to N do

begin Symb.Print; {вызвать метод родителя для вывода символа} inc(Col); inc(Line) {изменить позицию вывода}

end;

End;

Var Symbvar.Symb; {объявление объекта класса Symb } Lotvar: Lot; {объявление объекта класса L o t}

Begin

Symbvar.Init(l,1,80,25,7,1,40,12, A ’); {инициализироватьполя}

Symbvar.MakeWin;

{изобразить окно}

 

Symbvar.Print;

{вывести символ -

метод класса Symb}

Readkey;

Lotvar.Init(l, 1,80,25,7,1,40,12, ’В ’,10); {инициализироватьполя}

Lotvar.MakeWin;

{изобразить окно}

Lotvar.Print;

{вывести символы - метод класса Lot}

Readkey;

 

End.

 

По существу метод Print класса Symb и метод Print класса Lot - разные методы. Для объекта каждого класса вызывается метод, определенный в этом классе. По правилам Borland Pascal статические полиморфные методы могут иметь различные списки параметров в отличие от виртуальных полиморфных методов, рассматриваемых далее.

Слож ны й полиморфизм. При сложном полиморфизме конкретный аспект полиморфного метода также определяется типом объекта, для которого он вызван, но только не на этапе компиляции, а на этапе выполнения программы

(позднее связывание).

Необходимость позднего связывания обусловлена в частности тем, что в Borland Pascal разрешается указателю на объекты класса-родителя присваивать адрес объекта класса-потомка. Поскольку при передаче объектов в качестве параметров используются указатели, формально описанному параметру типа некоторого класса может соответствовать фактический параметр не только того же типа, но и типа класса, производного отуказанного.

В тех случаях, когда реальный тип объекта не определен, связывание объекта и метода на этапе компиляции программы приводит к тому, что при любых условиях (и для объектов родительских классов, и для объектов производных классов) вы зывается родительский метод (раздел 1.6). Применение позднего связывания позволяет правильно определить требуемый аспект полиморфного метода.

69

2. Средства ООП в Borland Pascal 7.0

Полиморфные методы, для которых применяется позднее связывание, называют виртуальными.

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

tual:

Procedure <имя метода>(<список параметров>); virtual;

Function <имя метода> (<список параметров>):<тип функции>; virtual;

При использовании виртуальных методов должны выполняться следующие правила.

1. Если в некотором классе метод описан как виртуальный, то все производные классы, включающие метод с тем же именем, должны описать этот метод как виртуальный. Нельзя заменить виртуальный метод статическим.

2.Порядок расположения, количество и типы формальных параметров в одноименных виртуальных методах должны оставаться неизменными.

3.Класс, содержащий виртуальные методы, должен включать специаль­ ный статический метод - конструктор. Для этого метода слово Procedure в объявлении и реализации должно быть заменено словом Constructor.

Конструктор неявно выполняет настройку механизма позднего связывания (обеспечивает связь объекта с ТВМ - раздел 1.6). Этот метод должен быть вызван до первого обращения к виртуальному методу, иначе происходит «зависание» компьютера. Как правило, конструктор использую т для инициализации полей объекта и, соответственно, называют blit.

Вызов виртуальных методов осуществляется через ТВМ, что требует дополнительного времени. В результате программа будет работать медленнее, чем при использовании статических методов. Однако использование виртуальных методов позволяет существенно увеличить гибкость описания классов.

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

1) полиморфный метод вызывается из статического метода родительского класса;

2) в программе используется процедура или функция с параметрами типа класса, которой в качестве фактического параметра может быть передан объект производного класса (процедура с полиморфным объектом), и эта функция вызывает полиморфный метод для объекта-параметра;

3) в программе используется указатель на базовый класс, которому может быть присвоен адрес объекта производного класса, и осуществляется вызов полиморфного метода для объекта по данному указателю.

П р и м е ч а н и е . При разработке библиотек универсальных классов полиморфные методы часто объявляют виртуальными, исходя из возможных вариантов дальнейшего использования.

70