Если родительский класс не задан, то компилятор автоматически в качестве родителя подставляет класс TObject. Тем самым все новые классы включаются в общую иерархию, что позволяет использовать ряд мощных механизмов, рассматриваемых в следующих разделах пособия.
В языке Java:
class Child extends Parent
{ новые свойства;
новые методы;
};
Здесь также при отсутствии родительского класса автоматически подставляется базовый класс Object и тем самым все классы включаются в общую иерархию.
В языке С++:
class Child : Parent1, Parent2, Parent3 // список родителей
{ новые свойства;
новые методы;
};
В качестве примера рассмотрим построение двух небольших библиотек классов:
· иерархия классов для основных графических примитивов;
· иерархия классов для основных структур данных.
Необходимо отметить, что построение иерархии классов не всегда бывает простым и очевидным и часто может быть выполнено различными способами.
Пример 1. На верхний уровень создаваемой иерархии необходимо поместить общий класс фигур. Этот класс целесообразно объявить абстрактным. Для фигуры надо ввести два свойства, которые затем будут наследоваться всеми подклассами. Эти свойства – координаты базовой точки – должны иметь любые примитивы-фигуры. В классе фигур можно ввести следующие абстрактные методы: показ фигуры (метод Show), перемещение базовой точки (метод MoveTo). Можно в классе ввести конструктор, но использовать его не для создания объектов (это запрещено для абстрактных классов), а для инициализации свойств-координат. Подклассами класса фигур можно сделать:
· класс Окружность (безусловно, окружность есть разновидность фигуры);
· класс Четырехугольник (это тоже разновидность фигуры).
В свою очередь, для класса Окружность можно создать два подкласса:
· класс Эллипс (с некоторыми оговорками эллипс можно считать сплюснутой окружностью);
· класс Дуга (тоже с некоторыми оговорками можно считать, что дуга – это разновидность окружности, для которой заданы начальный и конечный угол).
Графическое представление иерархии классов с использованием элементов языка UML выглядит следующим образом.
Пример 2. На верхний уровень иерархии структур данных можно поместить абстрактный класс с именем ADS (Abstract Data Structure), содержащим прототипы основных методов обработки любых структур (добавление, удаление, поиск, проверка наличия элементов). Потомками этого класса могут быть еще два абстрактных класса, определяющих статическую реализацию на базе массивов и динамическую реализацию на основе адресных указателей. На более низком уровне могут находиться реальные классы для реализации конкретной структуры (список, стек, очередь, дерево).
Класс ADS
Count : integer
Create; Add; Delete; Find; GetCount; IsEmpty;
При наследовании свойств и методов немного изменяется механизм доступа к элементам классов. Закрытые элементы класса по-прежнему доступны для прямого использования только объектам данного класса. Важно отметить, что эти элементы остаются закрытыми и для дочерних подклассов, т.е. закрытые элементы базового класса присутствуют в дочерних классах, но доступ к ним разрешен только через открытые методы родителя. Кроме двух стандартных уровней доступа (private и public) введен промежуточный уровень, описываемый директивой protected. Элементы с этой директивой, называемые по-русски защищенными,доступны для прямого использования в любых дочерних подклассах и только в них.
Большое значение при использовании наследования имеет правильное создание объектов дочерних классов. Поскольку дочерние подклассы практически всегда содержат больше свойств, чем их родители, то при создании дочернего объекта необходимо правильно инициализировать унаследованные свойства. За установку унаследованных свойств отвечает родительский конструктор, поэтому конструктор дочернего класса должен начинать свою работу с вызова конструктора родительского класса. Для этого используются специальные синтаксические приемы, отличающиеся для различных языков программирования.
В языке DP для вызова родительского конструктора используется директива inherited:
inherited Create ( );
В языке Java – директива super:
super (параметры);
В языке С++ вызов родительского конструктора можно вставить в заголовок дочернего конструктора:
Circle::Circle (ax, ay, ar): Figure (ax, ay);
В итоге создается вложенная цепочка вызовов конструкторов. В первую очередь устанавливаются поля, объявленные в классе самого верхнего уровня. После этого управление возвращается на уровень ниже с установкой соответствующих полей и т.д., и в последнюю очередь устанавливаются уникальные поля создаваемого объекта.
Например, для иерархической цепочки Фигура-Окружность-Дуга порядок инициализации свойств при создании объекта-дуги будет следующим: