Бертран Мейер - Основы объектно-ориентированного программирования
- Название:Основы объектно-ориентированного программирования
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Бертран Мейер - Основы объектно-ориентированного программирования краткое содержание
Фундаментальный учебник по основам объектно-ориентированного программирования и инженерии программ. В книге подробно излагаются основные понятия объектной технологии – классы, объекты, управление памятью, типизация, наследование, универсализация. Большое внимание уделяется проектированию по контракту и обработке исключений, как механизмам, обеспечивающим корректность и устойчивость программных систем.
В книге Бертрана Мейера рассматриваются основы объектно-ориентированного программирования. Изложение начинается с рассмотрения критериев качества программных систем и обоснования того, как объектная технология разработки может обеспечить требуемое качество. Основные понятия объектной технологии и соответствующая нотация появляются как результат тщательного анализа и обсуждений. Подробно рассматривается понятие класса - центральное понятие объектной технологии. Рассматривается абстрактный тип данных, лежащий в основе класса, совмещение классом роли типа данных и модуля и другие аспекты построения класса. Столь же подробно рассматриваются объекты и проблемы управления памятью. Большая часть книги уделена отношениям между классами – наследованию, универсализации и их роли в построении программных систем. Важную часть книги составляет введение понятия контракта, описание технологии проектирования по контракту, как механизма, обеспечивающего корректность создаваемых программ. Не обойдены вниманием и другие важные темы объектного программирования – скрытие информации, статическая типизация, динамическое связывание и обработка исключений. Глубина охвата рассматриваемых тем делает книгу Бертрана Мейера незаменимой для понимания основ объектного программирования.
Основы объектно-ориентированного программирования - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
[x]. f доступен классу B , - экспортирован всем классам или множеству классов, включающих B ;
[x]. d принадлежит типу T . Если учитывать возможность наследования, то d может принадлежать потомкам T .
[x].Результат вызова имеет тип U . В этом примере предполагается, что компонент f является функцией.
Теперь предположим, что C родовой класс с формальным родовым параметром G имеет компонент:
h (a: G): G is...
Вызов h имеет вид y.h(e) , где y сущность, объявленная как
y: C [V]
Тип V - некоторый ранее определенный тип. Теперь правило типизации - двойник неродового правила - требует, чтобы e имело тип V или при наследовании было потомком V . Аналогичное требование к результату выполнения функции h .
Требования правила понятны: V - фактический параметр, заменяющий формальный родовой параметр G параметризованного класса C , поэтому он заменяет все вхождения G при вызове компонент класса. Все предыдущие примеры следовали этой модели: вызов s.put(z) требует параметра z типа POINT , если s типа STACK [POINT] ; INTEGER если s типа STACK [INTEGER] ; и s.item возвращает результат типа POINT в первом случае и типа INTEGER во втором.
Операции над сущностями родового типа
В родовом классе C [G, H, ...] рассмотрим сущность, чей тип - один из формальных родовых параметров, например x типа G . Когда класс используется клиентом для объявления сущностей, G , разумеется, может представлять любой тип. Поэтому любая операция, которую выполняют подпрограммы C над x , должна быть применима ко всем типам. Это ограничение позволяет выполнять только пять видов операций:
Использование сущностей формального родового типа
Корректно использовать сущность x , чей тип задан формальным родовым параметром G , можно следующим образом.
1Слева от оператора присваивания x := y , где выражение y также имеет тип G .
2Справа от оператора присваивания y := x , где сущность y также типа G .
3В логических выражениях вида x = y или x /= y , где y также типа G .
4Как фактический аргумент в вызове подпрограммы на месте формальных параметров типа G , или типа ANY .
5Как цель вызова компонента класса ANY .
В частности, инструкция создания вида create xнеприменима, так как нам ничего неизвестно о процедурах создания, если таковые есть, для класса, определенного возможным фактическим родовым параметром, соответствующим G .
Случаи (4) и (5) ссылаются на класс ANY . Упомянутый уже несколько раз, этот класс содержит компоненты, наследуемые всеми классами. Поэтому можно быть уверенным, что независимо от фактического типа G при родовом порождении компоненты будут доступны. Компонентами класса ANY являются все основные операции копирования и сравнения объектов: clone , copy , equal , deep_clone , deep_equal и др. Поэтому для x и y формального родового типа G корректно использовать следующие инструкции:
x.copy (y)
x := clone (y)
if equal (x, y) then ...
Случай (4) разрешает вызов a.f(x) в родовом классе C [G] , если f имеет формальный аргумент типа G . В частности, возможна ситуация, когда a может быть типа D [G] , где D другой родовой класс. В классе D [G] объявлен компонент f , требующий аргумент типа G , обозначающий в этом случае формальный родовой параметр класса D , а не класса С . (Если предыдущая фраза не совсем понятна, перечитайте ее еще раз, и, надеюсь, она покажется столь же прозрачной 10.2) , как горный ручей.)
Типы и классы
Мы уже научились смотреть на класс - центральное понятие объектной технологии, - как на продукт слияния двух концепций: модуля и типа. До введения универсализации можно было говорить, что класс - это модуль, но это и тип данных.
С появлением универсализации второе утверждение перестало быть буквально истинным, хотя нюанс невелик. Родовой класс, объявленный как C [G] , является не типом, а шаблоном типа, задающим бесконечное множество возможных типов. Любой тип из этого множества можно получить, предоставив фактический родовой параметр, который, в свою очередь, является типом.
Это приводит к более общему и гибкому понятию. Но за выигрыш в мощности приходится немного пожертвовать простотой: только при небольшом насилии над языком можно продолжать говорить о "компонентах класса T " или о "клиентах T ", если x объявлен, как имеющий тип T . Теперь T может быть параметрически порожденным типом C [U] из некоторого родового класса C и некоторого типа U . Конечно, основой типа остается родовой класс C , поэтому насилие над языком приемлемо.
Если требовать буквальной строгости, то терминология следующая. Любой тип T ассоциируется с базовым классом T , поэтому всегда можно говорить о компонентах и клиентах базового класса T . Если T неродовой класс, то он же является и базовым классом. Если T родовое порождение C [U, ...] , то C является базовым классом T .
Базовые классы будут использоваться при введении еще одного вида типов, основанного также (как и все остальное в ОО-подходе) на классе, но косвенно: закрепленного типа (см. гл. 16.7). |
Массивы
В заключение этой дискуссии полезно рассмотреть пример контейнерного класса ARRAY , представляющего одномерный массив.
Массивы как объекты
Понятие массив обычно является частью определения языка программирования. В объектной технологии нет необходимости нагружать нотацию специальными заранее определенными конструкциями: массив - контейнерный объект, экземпляр класса, который можно назвать ARRAY .
ARRAY хороший пример родового класса. Рассмотрим первый набросок этого класса: 10.3)
indexing
description: "Последовательность значений одного типа или согласуемых типов,%
%доступных через целые индексы в заданном диапазоне"
class ARRAY [G] creation
make
feature
make (minindex, maxindex: INTEGER) is
-- Размещение массива с границами minindex и maxindex
-- (пустой, если minindex > maxindex)
Интервал:
Закладка: