Полиморфические объекты
При чтении предыдущего раздела вы, возможно, задали себе вопрос: "Если любой порожденный от типа параметра тип может пере- даваться в качестве параметра, то как же пользователь параметра узнает, какой тип объекта он получил?" Фактически, пользователь явно этого и не знает. Точный тип фактического параметра не из- вестен во время компиляции. Фактический параметр может быть объ- ектом любого дочернего от параметра-переменной типа, и именно по- этому он называется полиморфическим объектом.
Теперь, чем же именно хорош полиморфический объект? Прежде всего полиморфические объекты позволяют обрабатывать объекты, чей тип неизвестен на момент компиляции. Это общее замечание настоль- ко ново для образа мышления Паскаля, что пример для вас не поя- вится незамедлительно. (Со временем вы будете удивлены, насколько естественно это выглядит. То есть, когда вы действительно станете объектно-ориентированным программистом.)
Предположим, что вы написали инструментальное средство для вычерчивания графиков, поддерживающее многочисленные типы фигур: точки, окружности, квадраты, прямоугольники, кривые и т.д. В ка- честве части этого инструментального средства вы хотите написать программу, которая будет перемещать графическую фигуру по экрану с помощью устройства типа "мышь".
При старом способе необходимо было написать отдельную проце- дуру перемещения для каждого типа графической фигуры, поддержива- емой инструментальным средством. Вы должны были бы написать DragButterfly, DragBee, DragMoth и т.д. Несмотря на то, что стро- гая типизация (проверка типов) Паскаля позволяла это (и не забы- вайте, что всегда существуют способы обойти строгую типизацию), различия между типами графических фигур едва ли позволили бы на- писать действительно общую программу перемещения.
В конце концов, пчела имеет полоски и жало, бабочка имеет большие цветные крылья, а стрекоза имеет переливчатые цвета, хвост, да что говорить...
С этой точки зрения, "сообразительные" программисты, работа- ющие на Турбо Паскале, сделают шаг вперед и скажут: "Поступайте так: передайте запись о крылатом насекомом процедуре DragIt в ка- честве ссылки указателя общего вида. В процедуре DragIt проверяй- те свободное поле по фиксированному смещению внутри записи о крылатом насекомом для определения, какого вида это насекомое, а затем сделайте переход с помощью оператора case:
case FigureIDTag of Bee : DragBee; Butterfly : DragButterfly; Dragonfly : DragDragonfly; Mocquito : DragMocquito; . . .
Ну, размещение семнадцати маленьких чемоданчиков внутри од- ного большого является незначительным шагом вперед, но в чем же заключается проблема, ожидающая нас на этом пути?
Что случится, если пользователь инструментального средства определит несколько новых типов крылатых насекомых?
В самом деле, что? Что если пользователь захочет работать со среднеазиатскими фруктовыми мухами? В вашей программе нет типа Fruitfly, поэтому DragIt не содержит метки Fruitfly в операторе case и, следовательно, отвергнет перемещение нового рисунка Fruitfly. Будучи представленным процедуре DragIt, Fruitfly будет выпадать из оператора case в ветвь else этого оператора как "не- распознанное насекомое".
Откровенно говоря, создание для продажи инструментального средства без исходного кода страдает этой проблемой. Инструмен- тальное средство может работать только с типами данных, которые "известны" ему, т.е. которые определены разработчиком инструмен- тального средства. Пользователь инструментального средства оказы- вается бессильным перед расширением его функций в направлении, не предвиденном разработчиком. То, что пользователь купил, то он и получил. И точка.
Выходом из проблемы является использование правил расширен- ной совместимости типов Borland Pascal для объектов и разработка прикладных программ с использованием полиморфических методов. Ес- ли процедура DragIt инструментального средства установлена так, что может работать с полиморфическими объектами, то она будет ра- ботать с любыми объектами, определенными в инструментальном средстве, и с любыми дочерними объектами, которые вы определите сами. Если типы объектов инструментального средства используют виртуальные методы, то объекты и программы инструментального средства могут работать со сделанными вами графическими фигурами в собственных терминах самих фигур. Определенный вами сегодня виртуальный метод может вызываться файлом модуля (.TPU, .TPW или . TPP) инструментального средства, который был написан и оттранс- лирован год назад. Объектно-ориентированное программирование дает такую возможность, а виртуальные методы являются ключом к ней.
Понимание того, как виртуальные методы делают возможными та- кие вызовы полиморфических методов требует пояснения описания и использования виртуальных методов.