Мир программирования

 


Найти: на:


Меню
Партнеры
Счетчики
Реклама

Расширяемые объекты


 Предыдущая страница     |     Следующая страница  
Добавить в избанное Обсудить в форуме Написать автору сайта

         Люди, впервые  столкнувшиеся  с  Паскалем,  считают само собой разумеющимся гибкость стандартной процедуры  Writeln,   позволяющей одной процедуре обрабатывать параметры нескольких различных типов:

     Writeln(CharVar); {выводит значение символа}

     Writeln(IntegerVar); {выводит целочисленное значение}

     Writeln(RealVar); {выводит значение с плавающей точкой}

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

     Объектно-ориентированное программирование  решает эту проблему посредством наследования:  когда задается родительский тип,  методы родительского типа   наследуются,   но при необходимости они так же могут быть перекрыты.  Чтобы перекрыть родительский метод,   просто задайте новый метод с тем же именем, что и родительский метод, но с другим телом и (если необходимо) с другим набором параметров.

     Рассмотрим простой пример. Давайте зададим тип, порожденный от Point, который рисует окружность вместо точки на экране:

     type

     Circle   = object (Point)

       Radius : Integer;

       procedure Init(InitX, InitY : Integer; InitRadius : Integer);

       procedure Show;

       procedure Hide;

       procedure Expand(ExpandBy : Integer);

       procedure Contract(ContractBy : Integer);

     end;

      constructor Circle.Init(InitX, InitY : Integer;  InitRadius : Integer);

     begin

        Point.Init(InitX, InitY);

        Radius := InitRadius;

     end;

      procedure Circle.Show;

     begin

        Visible := True;

        Graph.Circle(X, Y, Radius);

     end;

      procedure Circle.Hide;

     var

        TempColor : Word;

     begin

        TempColor := Graph.GetColor;

        Graph.SetColor(GetBkColor);

        Visible := False;

        Graph.Circle(X, Y, Radius);

        Graph.SetColor(TempColor);

     end;

      procedure Circle.Expand(ExpandBy : Integer);

     begin

        Hide;

        Radius := Radius + ExpandBy;

        if Radius < 0 then Radius := 0;

        Show;

     end;

      procedure Circle.Contract(ContractBy : Integer);

     begin

        Expand(-ContractBy);

     end;

      procedure Circle.MoveTo(NewX, NewY : Integer);

     begin

        Hide;

        X := NewX;

        Y := NewY;

        Show;

     end;

      Окружность, в некотором смысле,  является жирной точкой:   она имеет все,     что    имеет    точка   (позицию   X,Y,    состояние видимый/невидимый) плюс радиус.  Объектный тип Circle появился  для того, чтобы  иметь единственное поле Radius,  но не забывает о всех других полях,  которые Circle наследует как наследник  типа  Point. Circle имеет X,Y и Visible, даже если Вы не видите их в определении типа для Circle.

     Так как Circle задает новое поле Radius,  то его инициализация требует нового Init метода,  который инициализирует Radius,  так же как  и  наследуемые  поля.  Вместо  прямого  присваивания  значений наследуемым полям,  почему бы не использовать повторно Point  метод инициализации  (иллюстрируемый  первым  оператором  в Circle.Init). Синтаксис для  вызова  наследуемого  метода:  Ancestor.Method,  где Ancestor - это идентификатор родительского типа объекта, а Method - идентификатор метода этого типа.

     Заметим, что  вызов  перекрывающего  метода  является не очень хорошим стилем; вполне возможно,  что Point.Init (или Location.Init для этого  случая)  выполняет более важную,  скрытую инициализацию. Путем вызова перекрывающего метода Вы обеспечите  включение  в  тип объекта, являющегося потомком, функциональности родителя. Вдобавок, любые изменения,  сделанные в родительском  методе,   автоматически влияют на всех его потомков.

     После вызова Point.Init,  Circle.Init  может  затем  выполнить свою собственную  инициализацию,   которая  в данном случае состоит только в присвоении Radius значения, передаваемого в InitRadius.

     Вместо изображения  и  удаления  окружности  по  точке,  можно использовать BGI Circle процедуру.   Если  Вы  поступите  так,   то потребуются новые Show и Hide методы, перекрывающие такие же методы в Point.  Такие переписанные заново Show и Hide методы появились  в приведенном выше примере.

     Уточнение имени с помощью точки разрешает  возможную  проблему освобождения от имени типа объекта, являющегося таким же, что и имя BGI программы,  рисующей тип объекта на экране.  Graph.Circle - это совершенно однозначный  способ  сказать  Turbo   Pascal,   что   Вы ссылаетесь  на  Circle  программу  в GRAPH.TPU,  а не на Circle тип объекта.

      Важно!

     В то  время,   как  методы  можно  перекрывать,   поле  данных перекрывать нельзя.  Если однажды Вы задали поле данных в  иерархии объектов, порожденный тип не может задать поле данных с точно таким же идентификатором.

[оглавление]


Предыдущая страница     |     Следующая страница


Добавить в избанное Обсудить в форуме Написать автору сайта

Опрос

Конкурсы
Реклама

 

Web дизайн: Бурлаков Михаил    

Web программирование: Бурлаков Михаил

Используются технологии uCoz