- •15. Основы объектно-ориентированного программирования
- •15.1. Основные понятия
- •15.2. Объявление классов объектов
- •15.3. Статические и динамические объекты
- •15.4. Правила построения и использования объектов а. Правила наследования
- •Б. Виртуальные методы
- •В. Ранее и позднее связывание
- •Г. Совместимость классов объектов
- •Вопросы для самоконтроля
15.3. Статические и динамические объекты
Чтобы создать объект, надо выполнить его конструктор.
Статический объект создается в статической области памяти программы. На этапе компиляции для него выделяется память, а при выполнении конструктора в эту память записываются значения полей (свойств объекта) и адреса точек входа в методы.
Для того, чтобы создать объект в динамической области памяти используют процедуру New. При этом возможны два способа создания объекта:
Первый заключается в выполнении двух действий: вначале получить необходимую память для объекта, используя процедуру New, а затем выполнить конструктор Init (этот процесс изображен ниже для объекта PL1^).
Второй способ основывается на модифицированной процедуре New, которая имеет два параметра: первый – имя переменной – указателя на объект, а вторая – вызов конструктора.
Так, запись
New(PL2, Init(130,251,Red));
имеет следующий смысл: выделить для объекта память в динамической области, вернув указатель на нее в переменную PL2, и выполнить конструктор для этого объекта, установив его свойства следующими: координаты (x=130, y=251) и красный цвет.
Вместе с модифицированной процедурой New для обеспечния работы с объектами можно использовать и модифицированную процедуру освобождения памяти из динамической области Dispose, в которой также имеется два параметра. Покажем это на примере уничтожения объектаPL2:
Dispose(PL2, Done);
Эта запись означает следующее: уничтожить объект, на который указывает переменная PL2, и затем освободить занимаемую им память.
Иллюстрация сказанного приведена ниже.
Type
Ppoint=^TPoint;
{тип
– указатель на объект} Var L1:
TPoint; {имена
статических объектов} PL1,
PL2 : PPoint; {имена
динамических объектов,
точнее
– имена указателей на объекты,
которые
будут созданы в динамической
области
программы} .
. .
begin L1.Init(10,20,Blue);
{создать
статический объект «точка»}
PL1:=New(PPoint);
{запросить
память под объект}
PL1^.Init(10,20,Blue);{и
создать его}
New(PL2,
Init(130,251,Red)); {второй
вариант создания
динамического
объекта, за счет модифицированной
процедуры New} .
. . L1.Show;
{Показать
на экране объект} PL2^.Show;
{Показать
на экране объект} PL2^.MoveTo(45,30);
{Переместить
объект на новое место} .
. . Dispose(PL2,
Done); {Уничтожить
объект и освободить память} .
. .
Т
Type PCircle
= ^TCircle; Tcircle
= object
(TPoint) {Класс
типа Окружность} Radius
: integer; { радиус
} Constructor
Init(ix,iy:integer; {кординаты}
iRadius:integer;
{}
icolor:
byte); {цвет} procedure
Show;virtual; end;
PRect
= ^TRect; TRect
= object(TPoint)
{
Класс
типа Прямоугольник} Width,Height
: integer; {} Constructor
Init(ix,iy:integer; {кординаты}
iWidth,IHeight:integer;
{}
icolor:
byte); {цвет} procedure
Show;virtual; end;
Оба класса являются потомками класса TPoint и в силу этого наследуют все методы родительского класса. Из объявления классов потомков видно, что для них требуется всего два метода – конструктор иShow. Наличиеконструктора обязательно для любого класса объектов, если дочерний класс имеет новые свойства (поля). А методShow необходим в связи с тем, что объекты каждого класса ”выглядят” иначе, чем другие.
Как видно из объявления иерархии классов, в каждом классе объявлен метод c одним и тем же именемShow, но реализующий неодинаковые алгоритмы. Это и есть пример полиморфизма имени Show.
А теперь можно вернуться к объяснению назначения атрибута virtual. При рассмотрении классаTPointмы описали логику методаHide следующим образом: установить цвет объекта равным цвету фона и выполнить его (объекта) метод Show. В этом описании никак не детализировался алгоритм последнего метода: Мы использовали то обстоятельство, что объект сам себя умеет нарисовать. Но такое же утвердение справедливо и для объектов вновь объявленных классов – они тоже умеют себя нарисовать, и следовательно, алгоритм унаследованного ими метода Hide полностью подходит и для них (потомков).
Единственная проблема, которая может оказаться существенной – в методе Hide нет указания того, какому классу принадлежит вызываемый в нем метод Show.Так вот, если в объявлении класса TPoint убрать атрибут virtual, то при выполнении метода Hide будет вызываться метод Show класса TPoint, а при его наличии будет осуществляться поиск метода Show в том классе, которому принадлежит объект. Именно по этой причине в объявлении новых классов даже не упоминается виртуальный метод Hide, хотя его логика соответствует объектам именно этх классов.
Ниже приведено объявление еще одного класса – строки текста. Этот класс построен как потомок класса TRect. Выбор такого наследования связан с тем, что срока текста занимает прямоугольник. Как расположена точка «привязки» этого прямоугольника относительно текста, можно увидеть из конструктора класса (TText.Init). А его методShowпоказывает, как будет выглядеть объект.
Type
PText
= ^TText; TText
= object(TRect)
{потомок
класса Прямоугольник} Txt:string;
{текст,
отображаемый на экране} Constructor
Init(ix,iy:integer; {кординаты} itext:string;
{текст} icolor:
byte); {цвет} procedure
Show;virtual; end;
Constructor
TText.Init(ix,iy:integer; {кординаты} itext:string;
{текст} icolor:
byte); {цвет} var w,h:integer; begin
w:=(Length(itext)+2)*TextWidth('W'); h:=2*TextHeight('W'); Inherited
Init(ix,iy,w,h,icolor); txt:=itext; end;
procedure
TText.Show; var TempColor:byte; begin TempColor:=GetColor;
SetTextJustify(CenterText,CenterText); SetColor(color); OutTextXY(x+width
div
2,y+height div
2,txt); SetColor(TempColor); Visible:=true; end;
Ниже приведен фрагмент программы, иллюстрирующий работу с объектами описанных классов.
.
. . . var c1:PCircle; r1:PRect; t1:PText; .
. . . begin .
. . . Инициализация
графического режима (Здесь
не показана) .
. . . New(c1,
Init(120,120,20,Yellow));{создание
объекта
«окружность»} c1^.Show; c1^.Drag(2); Dispose(c1,
Done); {уничтожение
объекта «окружность»}
Продолжение на следующей странице
New(r1,
Init(10,10,45,20,red));
{создание
объекта
«прямоугольник»} r1^.Show; r1^.MoveTo(50,24);
New(t1,
Init(300,300,'Example',Magenta));
{создание
объекта
«строка
текста»} t1^.Show; t1^.Drag(5); repeat
until KeyPressed; CloseGraph; end.
