Файл: 7. Взаимодействие классов на основе наследования.pdf

Добавлен: 20.10.2018

Просмотров: 1378

Скачиваний: 15

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 

 

объявляются  свойства  и  методы,  наследуемые  всеми  классами.  В  языках 

Java и С# этот класс называют  Object, в Delphi Pascal – TObject. Несмотря 

на общность названия, структура этих классов в разных языках различная. 

В  чем  же  состоит  мощь  принципа  наследования?  Для  трех-четырех 

классов,  связанных  отношением  наследования,  вряд  ли  стоит  ожидать 

каких-то существенных преимуществ. Мощь иерархии классов проявляется 

для  больших  разветвленных  наборов,  содержащих  десятки  и  сотни 

взаимосвязанных  классов.  В  такой  иерархии  можно  найти  один  или 

несколько  наиболее  подходящих  для  решения  конкретной  задачи  классов, 

причем  если  какой-то  существующий  класс  не  полностью  отвечает 

необходимым  требованиям,  на  его  основе  можно  легко  создать  класс-

потомок,  добавив  недостающие  свойства  и  методы  и  даже  изменив 

реализацию  некоторых  из  унаследованных  методов.  В  целом  это 

существенно  сокращает  время  разработки  новой  программы,  позволяет 

максимально  использовать  ранее  созданный  и  отлаженный  код,  повышает 

надежность программы и облегчает ее модернизацию.  

Механизм  наследования  между  классами  в  разных  языках  включается 

очень  легко  и  практически  одинаково:  имя  родительского  класса 

прописывается в заголовке нового класса. 

В языке Delphi Pascal: 

     TChildClass = class (TParentClass) 

         private  

               новые свойства; 

         public 

                новые методы; 

      end;   

Если  родительский  класс  не  задан,  то  компилятор  автоматически  в 

качестве родителя подставляет класс TObject. Тем самым все новые классы 

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

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


background image

 

 

В языке Java: 

   class    ChildClass   extends   ParentClass 

// очень удачная директива extends  (расширение)  

     { новые свойства; 

        новые методы;   

       }; 

Здесь  также  при  отсутствии  родительского  класса  автоматически 

подставляется базовый класс  Object и тем самым все классы включаются в 

общую иерархию. 

В языке С#: 

   class   ChildClass : ParentClass  

      { новые свойства; 

         новые методы;   

        }; 

Практически  также  –  для  языка  С++,  только  список  родителей  может 

содержать несколько классов: 

   class   ChildClass : Parent1, Parent2, Parent3     // список родителей 

 

При  наследовании  свойств  и  методов  немного  изменяется  механизм 

доступа  к  элементам  классов.  Закрытые  элементы  класса  по-прежнему 

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

Важно  отметить,  что  эти  элементы  остаются  закрытыми  и  для  дочерних 

классов,  т.е.  закрытые  элементы  базового  класса  присутствуют  в  дочерних 

классах,  но  доступ  к  ним  разрешен  только  через  открытые  методы 

родителя.  

Довольно  часто  такая  закрытость  является  неудобной,  поэтому  кроме 

двух  стандартных  уровней  доступа  (private  и  public)  введен 

промежуточный  уровень,  описываемый  директивой  protected.  Элементы 

класса,  объявленные  с  этой  директивой,  называют  защищенными,    и  они 

доступны  для  прямого  использования  в  любых  производных  классах  и 


background image

 

 

только  в  них.  Для  всех  остальных  классов,  не  входящих  в  подиерархию  с 

заданным корневым классом, эти элементы остаются закрытыми. 

Большое значение при использовании наследования имеет правильное 

создание  объектов  дочерних  классов.  Поскольку  дочерние  классы  всегда 

содержат  больше    свойств,  чем  их  родители,  то  при  создании  дочернего 

объекта  необходимо  правильно  инициализировать  унаследованные 

свойства.  За  установку  унаследованных  свойств  отвечает  конструктор 

родительского  класса,  поэтому  конструктор  дочернего  класса  должен 

начинать  свою  работу  с  вызова  конструктора  родительского  класса.  Для 

этого  используются  специальные  синтаксические  приемы,  отличающиеся 

для различных языков программирования.  

В  языке  DP  для  вызова  родительского  конструктора  используется 

директива inherited: 

inherited   Create ( );   //  вызов конструктора родительского класса 

В языке Java – директива super: 

super (параметры); 

В  языках    C#    и    С++  вызов  родительского  конструктора  можно 

вставить в заголовок дочернего конструктора: 

ChildClass ( . . . ) : ParentClass ( . . . ); 

В  итоге  создается  цепочка  вложенных  вызовов  конструкторов.  В 

первую  очередь  устанавливаются  поля,  объявленные  в  классе  самого 

верхнего уровня. После этого управление возвращается на уровень ниже с 

установкой  соответствующих  полей  и  т.д.,  и  в  последнюю  очередь 

устанавливаются уникальные поля создаваемого объекта. 

 

В  качестве  примера  использования  механизма  наследования 

рассмотрим  построение  небольшой  иерархии  классов  для  основных 

графических  примитивов.  Необходимо  отметить,  что  построение  иерархии 

классов  не  всегда  бывает  простым  и  очевидным  и  часто  может  быть 

выполнено различными способами. 


background image

 

 

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

общий  класс  фигур,  который  целесообразно  объявить  абстрактным.  Для 

фигуры  надо  ввести  два  свойства,  которые  затем  будут  наследоваться 

всеми производными классами. Эти свойства – координаты базовой точки – 

должны иметь любые конкретные фигуры.  

В классе фигур можно ввести два  абстрактных метода: показ фигуры 

(метод  с  именем,  например,    Show),  перемещение  базовой  точки  (метод  с 

именем MoveTo). Целесообразность их введения объясняется тем, что в этом 

случае  в  базовом  классе  как  корневом  для  создаваемой  подиерархии 

определяется общая функциональность, которую должны обеспечивать все 

конкретные  классы.  Заголовки  этих  абстрактных  методов  можно 

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

фигур.  

Можно  в  классе  ввести  конструктор,  но  использовать  его  не  для 

создания  объектов  (это  запрещено  для  абстрактных  классов),  а  для 

инициализации свойств-координат. Что касается методов доступа к полям 

данных, то здесь возможны два варианта: 

  поля  данных  (координаты  точки)  объявляются  закрытыми  и  для 

работы с ними как обычно вводятся методы доступа 

  поля  данных  объявляются  защищенными  и  тогда  методы  доступа 

можно не вводить 

Сам класс фигур достаточно простой и особых комментариев не требует. 

TFigure = class   // по умолчанию родитель – класс  TObject 

    private        //  альтернативный вариант – защищенные свойства 

          x, y : integer

    public 

          constructor  Create (ax, ay : integer); 

          procedure  SetXY (ax, ay : integer);  // можно не включать 

          function  GetX : integer;   // можно не включать 


background image

 

 

          function  GetY : integer;   // можно не включать 

          procedure Show;  abstract

          procedure  MoveTo(ax, ay : integer);  abstract

    end; 

    //  реализация неабстрактных методов 

class   Figure  {              // по умолчанию родитель – класс  Object 

    private   int  x, y;     //  альтернативный вариант – защищенные свойства 

    public   Figure (int  ax,  int  ay) {…;} 

    public   void  SetXY (int  ax,  int  ay) {…;}  // можно не включать 

    public   int   GetX( ) {…;}   // можно не включать 

    public   int   GetY( ) {…;}   // можно не включать 

    public   abstract   void   Show( );  

    public   abstract    void   MoveTo(int  ax,  int  ay); 

  };

 

 

Первый  дочерний  класс  –  это  класс  окружностей  со  следующей 

структурой: 

  одно  закрытое  или  защищенное  поле  для  радиуса  окружности  (а  вот 

поля  для  координат  центра  будут  наследоваться  из  базового  класса 

фигур) 

  конструктор для создания окружности 

  методы  доступа  к  радиусу  (методы  доступа  к  координатам  будут 

наследоваться) 

  реальные методы отображения и перемещения окружности 

Прежде  чем  привести  формальное  описание  класса  окружностей,  надо 

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

и перемещения? На первый взгляд – любые осмысленные, типа ShowCircle, 

MoveCircle.  Однако  на  самом  деле  следует  использовать  те  же  имена,  что 

были введены в базовом классе, например – Show и  MoveTo. Объясняется 

это  тем,  что  использование  одинаковых  имен  для  обозначения