Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 48
Текст из файла (страница 48)
Определение интерфейсов является важнейшей задачей этапа проектирования (см. э 23Л.3л.). Модуль может иметь |>азличные интерфейсы для различных пользователей и довольно часто интерфейс разрабатывается задолго до прояснения деталей реализации. Приведем пример Рагвег с интерфейсом, отделенным от реализации: 218 8,2. Пространства имен 8.2.1. Имена с квалификаторами Пространстэо имен является областью эидимости. Обычные правила областей видимости применимы и к пространствам. Поэтому, если нмя предварительно объявлено в пространстне имен или ы охэатынасощей области, дальше его можно использовать без проблем.
Имя из другого пространства имен можно использовать при помощи явного указания этого пространства э качестве кэачификато(эа. 11апример: !! Раскесл — э(по квалификатор О квалификатор не требуется с!оп Ые Рагкег..!егт (6оо! де1) ( сгои6!е !еЯ= рпт (дес), гог (х) стась ((ехег:сиге!о6) ( саке Еехег. МИ„ !ей! '= рпт (1гие); 0 ) !э/ ! ехеп: — это квалифи ко тор 11' ~ ехеп: — это квалификп тор Д квалификатор не требуется Кэалифсскатор Рагкегс необходим, чтобы указать, что 1епп () объявлена э Рагкег, а не является некоторой глобальной функцией. Так как !егт () яэляется частом Рагкег, при обращении из нее к рпт () нет необходимости пользоваться кэалификатором, Однако, прп отсутствии кэалификатора Еехег переменная сигг !о!с считалась бы необъявленной, потому что члены пространства имен Еехег не находятся э области видимости э пространстве Рагкег.
8.2.2. Объявления ыв)по Если имя часто используется эне пределоэ своего пространства имен, довольно уто- мительно писать его каждый раз с кэаэ!ификатором. Рассмотрим пример: // обработка перв!сянихвирахсении с!оиЫе Рагкег рот (эоо! де1) ( (! (де1)Еехег уе! !одея () ктасЬ (Еехег:сиге 1ой) ( саке Еехег:й!!!МВЕЯ: О констп нта с пл а воющей т он кои 1.ехегсде1 1одеп (); ге1игп Еехегэпитуег па!ие; сике ЕехегээЛМЕ.
( с!ои6!ей и = 1а6!е~1.ехегэк1ппд ии!ие); 1Е (Еехег,уе! 1о!ееп () == Еехег:А$81Б!у) и = ехрг (1гие); В идеале, любая часть программы принадлежит некоторому логическому фрагменту !егаодулк!э>. Поэтому л!обое объявление и нетривиальной программе э идеале должно находиться э некотором пространстве, имя которого указывает на его роль э программе. Исключение составляет та!и (], которое должно быть глобальным, чтобы среда времени выполнения распознавала его как специальное пмя Я 8.3.3). Глава 8. Пространства иман и исключения 214 ге1итл и, // у нарны б инну с саге Е.ехе! МЕЛсЕс5 те1игп — рпт (Л не(, саге Еехе! ЕР с!оиЫе е = ехрг (1 ие,', (/ (Еехег сигг 1ой м Еехег ЯР( ге1итп ет от("ожидалась ("), Еехег де1 1ойел (1, /!пропустить скобкноу ге1игп е, саге Еехет ЕЛВ, те!игл 1, Йе/аиИ ге1 игл еггог !'ожидалось первичное всчражение (, // обработка первичны выражений доиб!е рг(т (Ьоо! де1,' ( ия!пд Еехет де1 1ойеп, ияслдЕехег ситг 1ой, игспд Егтог етгот, // использовать де! !ойеп из Еехег О использовать аот !ой изьехег //использовал!ь еггогиз Епог (г" (де/(де1 !ойеп ((, гтдсй (сигг 1ой(( саге Еехе~ МУМВЕ!с ,!/ константа с лловаюв(ей о!очной де1 !ойеп ((, ге!игп Еехег питбег оа!ие, спгеЕехег ЛАМЕ ( с!оиЫеЛ и =- 1аЫе(Еехег ггт!пд оа1ие(, с/ (де1 1 о йеп () == Еехет АБ БЕБ!У( о = ехрг (1гие(, ге!игл о, саяе Еехег МЕМУВ // унарныйлсинус ге1игп -рт!т (1тие(, саяе Еехег ЕР с!оиЫе е = ехрг (~гие), !/ (сигт 1ой М Еехег !(Р( те1игп еттог ( ожидалась ('(, де1 1ойел (ь // пропустить скобки '! ' ге1игл е, саяе Еехег ЕИВ, ге1итл !, с!е/аи!! те!игл еггог ( ожидалось первичное вьсражение'~, Непрерывное повторение квалификатора Еехег к тому же отвлекает внимание.
Эту многословность можно устранить ия!лд-обьпвлениел!, которое позволяет указать в одном месте, что де! 1ойеп () наход!моя в пространстве Еехег. Например: 215 8.2. Пространства имен патеярате Рагяег( двиб(е ргдт (Ьов(); доиЫе 1елп (Ьив((, с(оиб(е ехрг (Ьоо(); (сс испольэовали ие1 1оlтеп из Еекет Д использовить вшт 1о(с из(влет сс( использовить етю~ из Енот ия(пиЕехетие1 !о(ьеп; ия!ли Еекег витт 1об иятд Еттогсегтог, Это позволит нам упростить функции из Рагяег практически до их первоначального вида (6' 6.1.1): ((длножессие и десение с1оиЫе Ратяет. гетт (Ьио! ие1) доиб(е (е(1 = рпт (Ке(1 дог („) ятде(ь ',еитг 1об) ( саяе Еехег М((Е !е(1*= рмт ((гие), бгеаб; саяеЕекет(лЕ(т. (доиЫе д == рмт (1гие)) ( (е~Р (= д; Ьгеаб; ге1итп етгог (" деление на 0') с(е~аи(1 ге1игл (е!'Е Я мог бы включить имена лексем в пространство Рать ег.
Однако, я умышленно оставил их с квалнфпкаторами в качестве напоминания о зависимости Рагяег сн Еехег. 8.2.3. Директивы ыв)пс( Что если бяя мы задались целью упростить функции Рагяег в тонноопи до их первоначального вида? Это было бы разумной целью для большой програьчьськ которая преобразуется с целью использования пространств имен, исходя из программы с менее явно выраженной модульностью. ия(пд-директива делает доступными имена нз пространства имен почти точно так же, как если бы они были объявлены вне своих пространств (5 8.2.8).
Например: лат еярасе Рагяег ( дииЫе рсдт (Ьво(); ия(пд-обьявление вводит локальньш синоним. Такие синонимы следует делать как можно более локальными во цзбежанпе конф- ликтов плсен. Однако, все функции синтаксического анализатора используют анало- пшные наборы имен из других модулей. Поэтому мы можем поместить ия(пи-объяв- ление в определение пространства имен Рагяег; Глава 8. Пространства имен и исключения 216 доиб!е 1егт )Ьоо1), с)оиЫе ехрг)боо!) О делает доепиртиии все иие~а из1ехег Д! делает достипнили нее анена из Еггог ив!пр па теврасе Еехег; ив!пд патеврасе Еггог; Это позволит нам написать функции Рагьег в точности так, как мы это делали с само- го начала Я 6.1.1): )1 уинохеение и деление доиб)е Ригвег..гегт )боо! дег) дои Ые !еГ1 = рит )де!), уог )л) вт!1сб )сиге 1об)1 ми:.
1еГ1*= рпт )Ьие), бгеаб; 11 адно жение саве ШГ Д!'деление 12 )доиЫед==рпт )1 ие))( 1еГ1У=- д; Ьгеаб, ге1игп еггог )" деление на 0"); с1е~аи11 ге!из п 1еЯ; 8.2.4. Множественные интерфейсы До.лжно быть ясно, что созданное нами определение пространства Рагвег не является интерфейсом. который Рагвег предоставляет пользователям: наш Рагвег состоит пз набора объявлений, которые позволяют удобным образом реализовать функции синтаксическогоо анализкгора. Интерфейс жс пользователеи Рагвегдолжсн быть намного проще: питеврасе Рагвег) доиЫе ехрг ) Ьоо 1), ) К счастью, одновременно могут существовать два определения пространство ивен Рпгвег и каждое из нпх может быть использовано там, где зто удобнее.
Итак, про- странство Рагвегможно рассматривать как: )1) общу1о среду для функций, реализующих синтаксический анализатор. [2) внешний нптсрфсйс для пользователей синтаксического анализатора. Итак, кол драйвера та(п )) должен видеть только Глобальные ив!ад-директивы хороши для переписывания старого кода в новом стиле Ц 8.2.9). В других ситуациях их лучше избегать.
Можно сказать, что ив!пд-директива является средством композиции пространств имен Я 8.2.8). В функциях (и только в них) ив!од-дирекгливп используется для удобства формы записи (Ь 8.3.3.1). 217 8.2. Пространства имен (7ин(перфейс длл пользовотелеп' па те зри се Ра гее г ( доиЫе ехрг (Ьоо((, Функции же, реализующие синтаксический анализатор, должны видеть интерфейс, который мы сочли наилучшим для ныраження общей среды.
Л именно: 0 ~оопер4ейс длл розридотттов патезрасе Рагвег( доиЫе рггт (Ьооб; с1оиЫе 1егт (Ьоо!(, с(оиЫе ехрг (Ьоо1(; 11 использовитьие1 1оЬеп пз(ехег О использовать аит 1оЬ из Еехе! О испол ьзовопгь еггог из Епог из!пдйехеп,дег 1оЬеп, из1пийехеп.сиге 1ой из1пд Еггог .еггог, или в графическом ниде: Рагзег' Драйвер Рагзег Стрелки отражают отношения «использует предоставляемый интерфейс». Рагзег' — это «малый» интерфейс, предоставляемый пользователям. Имя Рагзер (читается «Рагзег штрих») не является идентификатором С++. Оно намеренно было выбрано, чтобы подчеркнуть, что этот интерфейс не имеет отдельного имени в программе.
Отсутствие отдельного имени не должно вызывать дополнительных затруднений, потому что программисты свободно придумывают различные имена для различных интерфейсов н потому что программа физически хранится (сьь 9 9.3.2) в виде нескольких файлов с различными именами. Интерфейс для разработчиков сщшакспческого анализатора шире, чем интерфейс, предназначенный для его пользователей. Подобный интерфейс в реальном модуле реальной системы менялся бы гораздо чаще, чем интерфейс пользонателя. Очень важно, что пользователи модуля (в пашем случае — гласи ((, нспользуюгцая Рагзег) изолированы от этих изменений Нам не требуется два отдельных пространства имен для выражения двух различных интерфейсов, но мы могли бы обеспечить и это, если бы возникла соответствующая потребность.
Разработка интерфейсов является одной пз самых важных задач на этапе проектирования — решая ее, можно получить как много пользы, так и массу неприятностей. Следовательно, стоит подробно рассмотреть, что мы пытаемся получить и обсудить несколько альтернатив. Помните, что предложенное выше решение янляется самым простым из рассматриваемых, и часто наилучшим. Его самым слабым местом является то, что оба интерфейса имеют одинаковые имена и что компилятор может не иметь достаточной информации для проверки согласованности двух определений пространства имен. Однако, обычно он в состоянии осуществить проверку. Полее того, компоновщик отланливает большинство ошибок, пропущенных компилятором.
Предложенное здесь решение я использую для обсуждения физичсс кого разбиения па модули Я 9.3) и рекомендую его при отсутстнни дополнительных логических ограничений (см, также з 8.2.7). 218 Глава 8, Пространства имен и исключения 8.2.4.1. Альтернативы при проектировании интерфейса Целью использования интерфейсов является сведение к минимуму зависимостей между различными частями программы.
Минимальные интерфейсы приводят к легким в цонпманилл, имеющим лучшие свойства в плане сокрытия данных, легче модифицируемым и быстрее компилируемым пролраммам. Когда речь идет о зависимостях, важно помнить, что компиляторы и программисты склонны применять примитивный подход типа «Если определение видимо в точке Х, то все, написанное в точке Х, зависит от всего определения». Пользуясь приведенными выше определениями, рассмотрим прллмер: 0 интерфейс длл ризриаоптиков питезрасе Рагзег) 0- г)а иЬ)е ехрг ) Ьаа)), 0" тгтат)) 0 Рагзег ехрг )Га)зе), 0- Функция тат )) зависит только лл Рагзег ехрг )), но требуется время, интеллект, опыт и т, д. для того, чтобы зто определить. Как следствие, люди и компиляторы в программах реального размера не рискуют и полагают, что там, где может существовать зависимость, она имеет место был ь. Как правило, такой подход прекрасно себя оправдывает.