Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции 26.27.doc
Скачиваний:
1
Добавлен:
11.07.2019
Размер:
88.58 Кб
Скачать

3. Свойства наследования и полиморфизма объектов.

Инкапсуляция, хотя и вносит определенный порядок в использование данных и процедур, однако не уменьшает их количества, т.к. определяет только правила использования собственных средств, сосредоточенных в капсуле.

Ещё одной важной и мощной идеей объектно-ориентированного программирования является наследование полей и методов объектов, т.е. возможность передавать свойства объектов-предков "по наследству" объектам-потомкам. Отношение наследования "предок-потомок" позволяет строить иерархию объектов так, что многие поля и методы описываются лишь однократно и затем используются многими объектами. Таким образом, можно существенно ограничить количество необходимых описаний процедур в сложной программе.

Любой объект может быть объявлен потомком ранее описанного объекта-предка. При этом объекту-потомку становятся доступны все методы своего предка и все структуры данных этого предка. Кроме того, объект-потомок вправе определить свои дополнительные поля и методы и даже перекрывать методы предка. Каждый объект имеет единственного предка (непосредственного), а каждый предок может иметь любое число потомков. Это обычные правила иерархии.

Свойство наследования распространяется по цепочке, образуя дерево родственных объектов. В этом дереве имеется один объект-корень, являющийся предком всех других объектов. Если иерархия хорошо продумана, то получается библиотека объектов, представляющая многообразие связанных объектов, используемых при разработке прикладных программ. Примером такой библиотеки является Turbo Vision - библиотека объектов для разработки текстовых интерфейсов в системе DOS.

В Турбо Паскале, чтобы объявить объект потомком некоторого объекта-предка необходимо после ключевого слова object в круглых скобках указать имя объекта-предка. При этом в описании объекта-потомка указываются только дополнительные поля и методы, отсутствующие у предка (или предков). Например:

type Line = object ( point); {объект- Линия, являющийся предком объекта point}

xe,ye:integer; {координаты точки-конца линии}

procedure set_line(x1,y1,x2,y2:integer) ;{установка линии}

procedure get_line(var x1,y1,x2,y2:integer) ; {получить координаты }

end {Line};

Для экземпляров объектов Line доступны все поля и методы объекта point и, кроме того, поля координат второй точки (Хе и Ye), а также методы set_line и get_line.

Оператор присваивания может быть использован для обмена информацией между родственными объектами. Однако допустим только односторонний обмен - от потомка к предку. Например, если объявить L1 как экземпляр объекта Line, то допустимо присваивание вида p1:=L1; но не наоборот.

В целом ряде случаев при создании объектов-потомков бывает важно не только дополнять поля и методы новыми, но и "перекрывать" старые методы, введенные в предках. Это возможно, т.к. объекты Турбо Паскаля наделены свойством полиморфизма.

Полиморфизм - это возможность называть различные процедуры (или функции) одинаковыми именами. Такая возможность не чужда многим естественным операциям. Достаточно вспомнить операцию +, которая в Турбо Паскале может означать и сложение целых чисел, и сложение вещественных чисел, и сцепление строк, и объединение множеств. Полиморфизм можно использовать и для любых методов объектов-потомков путем перекрытия, ранее описанных методов предков. Термин "перекрытие" здесь означает подмену одного метода другим с тем же именем и, возможно, тем же набором параметров. Можно выполнить перекрытие двумя способами: статически и динамически.

Статическое перекрытие - объявление для объекта-потомка нового метода с тем же именем и, если необходимо, с тем же набором параметров, что и у метода, объявленного для предка. В этом случае новый метод, согласно принятому в Турбо Паскале обычному "правилу действия имён" (которое мы рассматривали ранее, при описании механизма процедур), будет действовать таким образом, что "видимым " для объекта-потомка и всех его потомков будет новый метод, в то время как для объекта-предка будет действовать старый метод (недоступный теперь для объекта-потомка!). Такой механизм перекрытия недостаточно гибкий и имеет распространение только в одном направлении - к потокам. Более гибким является специально введенный для объектов механизм динамического перекрытия.

Динамическое перекрытие действует только в период выполнения программы и возможно только для перекрытия метода с тем же именем и тем же набором параметров метода, что и у объекта-предка. Для перекрытия метода он должен быть описан в объекте-потомке как виртуальный метод - с директивой virtual. Компилятор по директиве virtual создает таблицу виртуальных методов, хранящую адреса точек входа всех виртуальных методов. При этом для каждого типа объекта создается собственная таблица, так что каждый экземпляр объекта однозначно связан с таблицей.

Фактическое связывание объекта с методами (полями объекта) осуществляется при обращении к конструктору - специальному методу, который отличается от обычного метода лишь ключевым словом constructor, заменяющим ключевое слово procedure. При наличии виртуальных методов в описании объекта должен присутствовать хотя бы один конструктор. В момент обращения к конструктору в специальное поле объекта заносится адрес нужной таблицы виртуальных методов, в результате чего все виртуальные методы оказываются связанными с экземплярами объектов, и получают доступ к нужным полям. Таким образом, полиморфизм распространяется не только вниз к потомкам, но и вверх - к предкам.

Конструктор часто используется для инициализации объекта, хотя для действия механизма перекрытия это не является обязательным. Конструктор может быть вообще пустой процедурой, и, тем не менее, перекрытие будет выполнено правильно, поскольку оно действует непосредственно по заголовку constructor. Сам конструктор не может быть виртуальным методом.