Дж. Рамбо, М. Блаха - UML 2.0 - Объектно-ориентированное моделирование и разработка (1158633), страница 92
Текст из файла (страница 92)
384 Глава 18 ° Обьектно-ориеитированные языки В С++ имеется концепция пространства имен (пап1езрасе), которая позволяет ограничивать область действия наименований программных сущностей, однако не ограничивает доступ к ним. Класс помещается в пространство имен, если его объявление находится внутри этого пространства, и полным именем такого класса становится патезрасесс/аззпате.
Пространство имен может охватывать несколько файлов исходного кода, и в одном файле может быть определено несколько пространств имен. Символы одного пространства имен могут быть введены в другое при помощи директивы из/пя. Стандартные имена библиотеки С++ находятся в пространстве имен зи/. Если пространство имен не указано, символы считаются глобальными. Поскольку пространства имен ограничивают видимость, но не доступ, они используются главным образом для предотвращения совпадения имен при работе с несколькими библиотеками. Управление доступом в иерархиях наследования В обоих описываемых нами языках имеется спецификатор доступа ргогесгеИ, но работает он по-разному.
В С++ защищенный член класса доступен только методам класса и его подклассов. В)ача защищенные атрибуты и методы имеют пакетный уровень доступа, который расширяется включением методов подклассов, определенных вне пакета. В )ача отсутствует эквивалент защищенному уровню доступа из С++. Применение управления доступом В модели ПМЕ могут присутствовать обозначения /риЫ1с), /риоате), /рготестег/), /раскладе) или +, -, Ф, -, определяющие уровень доступа к членам класса (который в ПМЕ называется видимостью — ч1з1Ь|йгу).
Отсутствие явных указаний подразумевает, что метод принадлежит к общедоступному интерфейсу класса. В реализации модели необходимо использовать спецификаторы доступа, а вспомогательные атрибуты следует делать закрытыми. 18.3.4. Обобщение Объектно-ориентированные языки позволяют реализовывать обобщение через наследование. Класс может являться предком-суперклассом для одного или нескольких потомков-подклассов.
Подкласс наследует все элементы предка, к которым он может добавлять собственные атрибуты и методы. Подкласс может переопределять методы суперкласса, что позволяет ему по-своему выражать поведение метода с тем же именем и сигнатурой (параметрами и возвращаемым значением). Подклассы, в свою очередь, могут выступать в качестве суперклассов по отношению к своим потомкам. В результате получается иерархия классов, на которой каждый уровень выражает расширенное или конкретное поведение. Механизм наследования не только делает определение подклассов более удобным, он позволяет более абстрактным образом работать с объектами. Наследование делает возможным полиморфизм, благодаря которому тип потомка может выступать в качестве представителя типа предка.
В цельной иерархии каждый 18.3. Реализация структуры 385 подкласс должен уметь реализовывать поведение всех своих суперклассов так, чтобы он в любой ситуации мог осуществить ожидаемое от суперкласса поведение (! (якоч-881. Не обязательно определять все классы иерархии наследования полностью. Абстракции высокого уровня достаточно просто объявить, а реализацию деталей отложить до подклассов. В результате получатся абстрактные классы — описанные, но не реализованные полностью. Абстрактные классы описывают типы на уровне, не обладающем достаточными сведениями для реализации конкретного поведения. Например, любую фигуру можно нарисовать, но пока ее тип неизвестен, отсутствуют сведения о том, как это сделать.
Поскольку абстрактные типы реализованы не полностью, вы не можете создавать объекты этих типов. Вместо этого вы должны создавать конкретные объекты, принадлежащие к типу одного из конкретных подклассов, который должен полностью реализовывать определенное в суперклассе поведение (и свое собственное), и работать с ссылками на эти объекты, имеющими тип суперкласса. На объекты подкласса в этом случае можно ссылаться как иа объекты более общего типа.
Например, 5диа)в или С)гс!е — конкретные подклассы абстрактного класса 5ларе. Можно работать с ними через переменную-ссылку типа э/(аре. Хотя обе ссылки будут иметь тип 5йаре, при вызове метода йап)О будет выполняться соответствующее поведение. Приведенная ниже программа на языке 3ача приведет к построению разных форм. Яьаре з1 пен Сггс1е(); Яьаре »2 пен Яг(саге () ! з1.бган()! з2.оган()! Языки С++ и )ача реализуют разные модели наследования.
Наследование в За1/а Все объекты )ача имеют общего предка — класс 0)уесг. Он содержит минимальный набор методов и полей, необходимых для поддержки концепций программирования, таких как индивидуальность, эквивалентность и параллельность объектов. Наличие общего предка позволяет работать с объектами на максимально общем уровне: например, формировать совокупности различных, не связанных между собой типов. Использование объектов на уровне «бестиповой» абстракции позволяет обойти некоторые ограничения, накладываемые языками с жесткой типизацией. Наследование реализуется посредством ключевого слова ехал!)я: с1азв ассоппс ( рг1часе 11оас Ьа1апсе! рпЬ1»с чогб Ровс(11оас аиоппс) ( риь11с Г1оас Ва1апсе() ( геспгп Ьа1апсе! с1авв Яачгпввйссоппс ехсепг(в ассоппс ( рг1часе Г1оаг гаге! // добавление атрибута — сронентной ставки 11оас Са1с1пгегевс() ( // расчет причитагвзихсх пронентов !Э Зах 699 386 Глава 18 ° Объектно-ориентированные языки Класс языка 1ача может быть потомком только одного класса.
Однако некоторые преимущества множественного наследования можно реализовать посредством интерфейсов. Интерфейс ((пгег(асе) — это класс, определение которого не содержит реализации. Оно содержит объявления методов (без реализации) и может содержать неизменяемые поля, относящиеся к классу в целом (а не к отдельному объекту), то есть статические. Интерфейсы, как и классы, могут иметь потомков — субинтерфейсы.
Чтобы воспользоваться интерфейсом, класс должен объявить, что он реализует данный интерфейс, и предоставить код для всех методов интерфейса. Класс может расширять только один класс (то есть быть его потомком), но может реализовывать произвольное количество интерфейсов, что позволяет имитировать множественное наследование. Реализующий множество интерфейсов объект можно рассматривать как имеющий любой из типов своих интерфейсов.
В нашем примере мы абстрагируем счета, на которые начисляются проценты, в отдельный интерфейс, который будет реализовываться классом 5ап(пдзАссоипк Это гарантирует однородность методов во всех классах, реализующих данный интерфейс, как бы они ни назывались: 5аипдзАссоипг, 1пгегезгВеаппдо(есЫпдАссоипг или как-либо еше. 1лгегтасе 1пгегеягзеаг1лЧАссг ( 11оас Са1с1лсегеяс(): ) с1аяя Бачглчяассоцпс ехгелця Ассоцлс (ер1етелся 1лсегеясвеаг(лЧАссс ( рггчаге 11оаг гаге1 рцъггс 11оаг Са1с1пгегеяс() ( реализация вычисления процентов ) ) Теперь 5аипдзАссоипс может выступать в программе как объект типа Ассоипг, 5ап(пдяАссоипг или 1пгетезгВеаг(пдАссг.
Помимо конкретных классов и интерфейсов, в ) ага допустимы и абстрактные классы — не полностью реализованные классы, которые не могут иметь экземпляров, но могут быть предками конкретных подтипов. И сам класс, и его нереализованные методы должны иметь спецификатор абзйаск рцЬ1гс аЬясгасг с1аяя АЬясгассвхаир1е ( чо1Ц еегьоЦ1() ( Г*... *Г ) аЬясгасс чо1Ц еесьос2 ) Открытый класс может служить суперклассом подклассу в другом пакете, поскольку он доступен любому клиенту, импортировавшему пакет, в котором такой класс находится. Подклассы, определенные вне пакетов своих суперклассов, могут обращаться не только к открытым, но и к защищенным членам своих суперклассов.
Закрытые члены суперклассов подклассам не видны (см. раздел 18.3.3). Чтобы предотвратить порождение подклассов, класс следует объявить какала('. Квалнфикатор Япа(, примененный к методу, запрещает его перекрытие. 18.3. Реализация структуры 387 Наследование в С++ Подклассь( С++ не имеют общего предка. Иерархия классов может начинаться с произвольного класса.