ВУЗ: Университет управления «ТИСБИ»
Категория: Учебное пособие
Дисциплина: Объектно-ориентированное программирование
Добавлен: 20.10.2018
Просмотров: 1378
Скачиваний: 15
объявляются свойства и методы, наследуемые всеми классами. В языках
Java и С# этот класс называют Object, в Delphi Pascal – TObject. Несмотря
на общность названия, структура этих классов в разных языках различная.
В чем же состоит мощь принципа наследования? Для трех-четырех
классов, связанных отношением наследования, вряд ли стоит ожидать
каких-то существенных преимуществ. Мощь иерархии классов проявляется
для больших разветвленных наборов, содержащих десятки и сотни
взаимосвязанных классов. В такой иерархии можно найти один или
несколько наиболее подходящих для решения конкретной задачи классов,
причем если какой-то существующий класс не полностью отвечает
необходимым требованиям, на его основе можно легко создать класс-
потомок, добавив недостающие свойства и методы и даже изменив
реализацию некоторых из унаследованных методов. В целом это
существенно сокращает время разработки новой программы, позволяет
максимально использовать ранее созданный и отлаженный код, повышает
надежность программы и облегчает ее модернизацию.
Механизм наследования между классами в разных языках включается
очень легко и практически одинаково: имя родительского класса
прописывается в заголовке нового класса.
В языке Delphi Pascal:
TChildClass = class (TParentClass)
private
новые свойства;
public
новые методы;
end;
Если родительский класс не задан, то компилятор автоматически в
качестве родителя подставляет класс TObject. Тем самым все новые классы
включаются в общую иерархию, что позволяет использовать ряд мощных
механизмов, рассматриваемых в следующих разделах пособия.
В языке Java:
class ChildClass extends ParentClass
// очень удачная директива extends (расширение)
{ новые свойства;
новые методы;
};
Здесь также при отсутствии родительского класса автоматически
подставляется базовый класс Object и тем самым все классы включаются в
общую иерархию.
В языке С#:
class ChildClass : ParentClass
{ новые свойства;
новые методы;
};
Практически также – для языка С++, только список родителей может
содержать несколько классов:
class ChildClass : Parent1, Parent2, Parent3 // список родителей
При наследовании свойств и методов немного изменяется механизм
доступа к элементам классов. Закрытые элементы класса по-прежнему
доступны для прямого использования только в методах данного класса.
Важно отметить, что эти элементы остаются закрытыми и для дочерних
классов, т.е. закрытые элементы базового класса присутствуют в дочерних
классах, но доступ к ним разрешен только через открытые методы
родителя.
Довольно часто такая закрытость является неудобной, поэтому кроме
двух стандартных уровней доступа (private и public) введен
промежуточный уровень, описываемый директивой protected. Элементы
класса, объявленные с этой директивой, называют защищенными, и они
доступны для прямого использования в любых производных классах и
только в них. Для всех остальных классов, не входящих в подиерархию с
заданным корневым классом, эти элементы остаются закрытыми.
Большое значение при использовании наследования имеет правильное
создание объектов дочерних классов. Поскольку дочерние классы всегда
содержат больше свойств, чем их родители, то при создании дочернего
объекта необходимо правильно инициализировать унаследованные
свойства. За установку унаследованных свойств отвечает конструктор
родительского класса, поэтому конструктор дочернего класса должен
начинать свою работу с вызова конструктора родительского класса. Для
этого используются специальные синтаксические приемы, отличающиеся
для различных языков программирования.
В языке DP для вызова родительского конструктора используется
директива inherited:
inherited Create ( ); // вызов конструктора родительского класса
В языке Java – директива super:
super (параметры);
В языках C# и С++ вызов родительского конструктора можно
вставить в заголовок дочернего конструктора:
ChildClass ( . . . ) : ParentClass ( . . . );
В итоге создается цепочка вложенных вызовов конструкторов. В
первую очередь устанавливаются поля, объявленные в классе самого
верхнего уровня. После этого управление возвращается на уровень ниже с
установкой соответствующих полей и т.д., и в последнюю очередь
устанавливаются уникальные поля создаваемого объекта.
В качестве примера использования механизма наследования
рассмотрим построение небольшой иерархии классов для основных
графических примитивов. Необходимо отметить, что построение иерархии
классов не всегда бывает простым и очевидным и часто может быть
выполнено различными способами.
На верхний уровень создаваемой иерархии необходимо поместить
общий класс фигур, который целесообразно объявить абстрактным. Для
фигуры надо ввести два свойства, которые затем будут наследоваться
всеми производными классами. Эти свойства – координаты базовой точки –
должны иметь любые конкретные фигуры.
В классе фигур можно ввести два абстрактных метода: показ фигуры
(метод с именем, например, Show), перемещение базовой точки (метод с
именем MoveTo). Целесообразность их введения объясняется тем, что в этом
случае в базовом классе как корневом для создаваемой подиерархии
определяется общая функциональность, которую должны обеспечивать все
конкретные классы. Заголовки этих абстрактных методов можно
рассматривать как прототипы будущих реальных методов для конкретных
фигур.
Можно в классе ввести конструктор, но использовать его не для
создания объектов (это запрещено для абстрактных классов), а для
инициализации свойств-координат. Что касается методов доступа к полям
данных, то здесь возможны два варианта:
поля данных (координаты точки) объявляются закрытыми и для
работы с ними как обычно вводятся методы доступа
поля данных объявляются защищенными и тогда методы доступа
можно не вводить
Сам класс фигур достаточно простой и особых комментариев не требует.
TFigure = class // по умолчанию родитель – класс TObject
private // альтернативный вариант – защищенные свойства
x, y : integer;
public
constructor Create (ax, ay : integer);
procedure SetXY (ax, ay : integer); // можно не включать
function GetX : integer; // можно не включать
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. Объясняется
это тем, что использование одинаковых имен для обозначения