Р.У. Себеста - Основные копцепции языков программирования (2001) (1160794), страница 126
Текст из файла (страница 126)
Когда вызывается функция с(гам с указателем на базовый 'ласс этих производных классов, такой вызов должен быть динамически связан с функзией-членом соответствующего производного класса. Описанную ситуацию можно проиллюстрировать следуюшим примером: с1аее апаре ( риЬ11с: чзпсие1 чозс с(гам() = Оз ) с1еее сзкс1е: риЬ11с вЬаре ( 1 1.9. Поддержка объектно-ориентированного программирования... рпЬ1з.с: чйгкца1 чоЫ г)ган() ( ...
)г ) с1авв гессапо1е: рпЬ11с вПаре ( риЬ11с: чягпиа1 чо1с) с(гак() ( ) о1авв зг)цаге: рцЬ11с гесгапд1е ( риЬ11с: «дгп 1 да с)г () ( ... )г С учетом этих определений ниже приводятся примеры статически и динамически свя- занных вызовов в соответствии с данными выше определениями классов. вс)цаге з; гесгапд1е гг в)таре Ьгей эпаре вг // ссылка на квадрат в геб в)заре.бган()г // вызов, динамически связанный с // функцией бган в классе вг)цаге // вызов, статически связанньз7~ с функцией // г)ган в классе гесгапо1е г.г)гак()г 466 Глава 11. Поддержка объектно-ориентированном программирования Заметим, что функция с(ган в определении базового класса в)заре установлена равной нулю.
Этот особый синтаксис используется для указания на то, что эта функция-член является чисто виртуальной функцией (риге «(гШа) Йпс(юп), т.е. она не имеет тела и не может быть вызвана. Ее следует переопределить в производных классах. Цель чисто виртуальной функции — обеспечить интерфейс функции без указания ее реализации. Это новая форма сокрытия информации, или инкапсуляции. Любой класс, содержащий чисто виртуальную функцию, называется абстрактным классом (а(запас( с!азз). Ни один обьект абстракпюго класса не может быть создан.
Строго говоря, абстрактный тнп данных не может иметь конкретных объектов, а используется только двя представления концепции типа. Подклассы такого типа, конечно, могут иметь обьекты. Абстрактные классы в языке С++ используются для моделирования истинно абстрактных типов данных.
Если подкласс абстрактного класса не переопределяет чисто виртуальную функцию своего родительского класса, эта функция остается чисто виртуальной. Абстрактные классы и наследование вместе взятые представляют собой мощные средства для разработки программного обеспечения. Они позволяют иерархически определять типы, так что связанные между собой типы могут быть подклассами истинно абстрактных типов, определяющих их общие абстрактные свойства. Динамическое связывание позволяет писать код, использующий члены наподобие функции с(ган до того, как будут написаны все или даже хотя бы одна из версий функции с(гак. Новые производные классы могуг быть добавлены на много лет позже, и при этом в код, использующий такие динамически свюанные члены, не потребуется вносить никаких изменений.
Это мощное свойство объектно-ориентированных языков. 11.9.4. Оцвнка Естественно сравнить обьекгно-ориентированные свойства языков С++ и Зщайгайг, .то и сделано в этом разделе. Наследование в языке С++ более запутано, чем управление доступом в языке сщайга!И. Использование управления доступом в определении класса и в производных '.лассах наряду с возможностью объявлять дружественные функции и классы позволяет программисту на языке С++ осуществлять очень детализированное управление доступом ь членам класса. Более того, несмотря на то, что реальная ценность множественного наследования является предметом споров, язык С++ поддерживает его, в то время как язык %пайгайс позволяет использовать только одиночное наследование.
На языке С++ программист может сам определять, какое связывание следует использовать — статическое или динамическое. Поскольку статическое связывание выполняется быстрее, этот факт становится преимуществом в тех ситуациях, когда динамическое связывание не обязательно.
Кроме того, по сравнению с языком Бщайга(к лаже динамическое связывание в языке С++ выполняется быстрее. Связывание вызова виртуальной функции-члена с определением функции в языке С г+ имеет фиксированную стоимость независимо от того, насколько далеко в иерархии наследования это определение появляется. При вызове виртуальных функций требуется только иа пять обращений к памяти оольше, чем при статически связанных вызовах (Бггоцзпцр, 1988). В языке Бщайш!к, однако, сообщения всегда динамически связываются с методами, и чем дальше в иерархии наследования находится соответствующий метод, тем дольше выполняется его вызов.
Из-за того, что пользователь сам может определять, какие связывания являются статическими, а какие — динамическими, эти решения должны реализовываться в исходном проекте, в то время как позднее может потребоваться их изменить. Статическая проверка типов в языке С++ является значительным преимушеством над языком Бшайга!Е, в котором вся проверка типов осуществляется динамически. Программа на языке Бщайга!Е может быть скомпилирована с сообщениями, предназначенными для несуществующих методов, что обнаруживается затем при динамическом тестирова нии. В то же время компилятор языка С++ находит такие ошибки. Вообще говоря, ошибки, обнаруживаемые компилятором, легче исправить, чем ошибки, выявляемые во время выполнения программы.
Язык Бщайш(й в принципе не имеет типов, т.е. весь код является действительно настраиваемым. Это обеспечивает большую гибкость, но при этом приносится в жертву статическая проверка типов. Язык С++ обеспечивает создание настраиваемых классов с помощью шаблонных классов (как описано в главе 10), сохраняющих преимушества статической проверки типов. Основное преимушество языка Бтайшйс заключается в элегантности и простоте языка, являющейся результатом простой философии, лежащей в основе его разработки. Он исключительно и всецело посвящен объектно-ориентированной парадигме и избегает компромиссов, диктуемых прихотями устоявшейся пользовательской базы. Язык С++, с другой стороны, представляет собой большой и сложный язык без целостной философии, за исключением требования сохранить пользовательскую базу языка С.
Одна из основных целей создания этого языка — сохранение эффекпвности и особенностей языка С одновременно с обеспечением преимуществ объекпю.ориентированного программирования. Некоторые люди интуитивно чувствуют, что эти свойства языка С++ не всегда хорошо согласуются друг с другом и что в значительной степени сложность этого языка является излишней. 11.9. Поддержка объектно-ориентированного прогроммнровония... Как указано в работе СйашЬегз апб ()пйаг (1991), система Бшайгарк выполнила набор небольших тестов, написанных а стиле языка С, в 1О раз медленнее. чем оптимизированный язык С. Программы на языке С++ требуют лишь не намного больше времени, чем эквивалентные программы на языке С (Бггоцз(гор, 1988).
Учитывая большое различие в эффективности межлу языками Бтайга!й и С+~, не приходится удивляться тому, что язык С++ имеет намного более широкое коммерческое применение, чем язык Бшайгайь Конечно, существует много факторов, определяющих это различие, но эффективность, несомненно. является аргументом в пользу языка С++. 11Л О. Поддержка объектно-ориентированного программирования в языке Зача Поскольку реализация классов, наследования и методов в языках )ача и С++ аналогичны,мы сосредоточимся а этом разделе только на тех областях, в которых )ата значительно отличается от С++. 11.10.1.
Общие свойства Как н язык С++, )ача не использует исключительно объекты. Однако в языке )ата обьектами не являются только значения элементарных скалярных типов (булевского, символьного или численных типов). В нем нет типов перечисления или записи, а массивы представляют собой объекты. Причина, по которой в языке )ата используются сущности, не являющиеся объектами, заключается в эффективности. Однако, как указано в разделе 11.3.1, наличие двух систем типов приводит к некоторым затруднениям. Например, в языке /ата встроенная структура данных Чесгог может содержать только объекты.
Таким образом, если вы хотите поместить значение элементарного типа в объект типа иесг ог, это значение сначала следует поместить в некоторый объект. Это можно сделать, создав новый объект интерфейсного класса для элементарного типа. Такой класс имеет переменную экземпляра данного элементарного типа и конструктор, принимающий значение элементарного типа в качестве параметра и прнсваиваюший его своей переменной экземпляра. Например, чтобы поместить целое число 10 в объект типа Чесг ог, на который ссылается переменная п~ууес г ог, используем следующий оператор: жуЧесгог.аббЕ1ежепг(пан 1пге9ег(10)); Здесь аббчесгог — метод класса уесгог, вставляющий новый элемент, а 1пседег — интерфейсный класс лля простого типа спс.
В то время как в языке С++ классы могут не иметь родительских классов, в языке )ата это невозможно. Все классы в языке!ача должны быть подклассами корневого класса ОЬЗесг илн некоторого класса, являющегося потомком класса ОЬз ест. Причина, по которой в языке )ача имеется один корневой класс, состоит в том, что существуют некоторые операции, необходимые повсеместно.