Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 49
Текст из файла (страница 49)
Таким образом, нашей пелью является написание программы, в которой набор потенциальных зависимостей сведен к набору действительных зависимостей. Сначала мы пытаемся сделать очевидное: определить пользовательский интерфейс синтаксического анализатора в терминах интерфейса разработчика, который мы уже имеем; 0 интерфейс алл разработчиков патезрасе. Рагзег) 0" а)ииЫе ехрг )Ьаи)), 0 ) 0 интерфейс длл палвзавитвлеи палпезрасе Рагзег т!ег)иве( излпд Рагзег ехрг, Ясно, что пользователи Рагзег тле«тасе зависят только отРагзеглехрг)) (прпчем косвенно).
Г)оверхностный взгляд на схему зависимостей дает нам следующую картину: Рагзвг Ё Дра 219 8.2. Пространства имен )1 ин!перфейсдля тыьзовителеи патеврасе Рагвег ( с!ииЫе ехр! (Ьии!), ) О отдельный илвновинный инп!ерфейг 0дл.ч пользовителей патевраге Риглег т1ег)асе ( ив!пи Ригвегехрг; нли графически: Рагве!. Рагвег Рагхег !п1егуасе ( Драйвер ) И снова для проверки согласованности Рагьег и Рагвег' мы полагаемся на всю снстему компнляцпц, а нс на компиляцию отдельного модуля.
Это решение отличается от предложенного в 8 8.2А только дополнительным пространством имен Рагвег ьп1еггасе. Еслибы мы закотелп, мы могли бы включить вРагвег ьп1егГасе конкретное представление, введя его собственную функцию ехрг(): патеврасе Ригвег гп!егйисе ( дииЫе ехрг (Ьии)); Теперь Рагвег не обязан находиться в области внлимостн для того. чтобы мы могли определитьРагве! )п1еггасе.
Он должен быть видимым только там, где определяется Рагвег 1п1ег)асесехрг (): аииЫе Рагвег т!власе.ехрг(Ьии) ие1 ( ге1 ига Раглегзехрг (иег), ) Последний вар!лант можно представить графически следугогциы образом: Рагвег !п1ег)асе Рагвег я Рагхег Теперь все зависимости сведены к минимуму. Все конкретно н именовано соответ- ствующим образом. Однако, для большинства проблем, с которыми я сталкиваюсь, такое решение является неоправданно сложным. Теперь драйвер сильно записи~ от любых изменений в интерфейсе Рагвег, от которых мы хотели его изолировать. Даже такой внд зависимости является нежелательным, поэтому мы явно огранцчиваем зависимость Рагвег !п1ег)асе от Рагвег, оставив видимой только существенную часть интерфейса для разработчиков (ранес мы назвали ее Рагвег') при определении Рагвег ьл1егГасе: 220 Глава 8.
Пространства имен и исключения 8.2.5. Разрешение конфликтов имен Пространства имен предназначены для отражения логической структуры. Простейшим примером такой структуры является отделение кода, написанного одним человеком, от кода, написанного другим. Это простейшее разделение может иметь огромное практическое значение. При использовании единственной глобальной области видимости неоправданно сложно формировать программу из отдельных частей. Проблема состоит в том, что в каждой отдельной (предположительно) части могут определяться одинаковые имена.
Когда части объединяются в одну программу, происхолит конфликт имен. Рассмотрим пример: // ту.(и сдагЯслаг); 1л1/(1п(); с1азз 81г1пу(/' .. /)' // уои гоп слагЯслаг), с!оиЫе/(аооЫе); с!азз 81г!лу(/* ...'/); Прп наличии таких определений непросто использовать ту.й и уоиг.й одновременно. Очевидным решением является помещение каждого набора объявлений в свое собственное пространство имен: патезрисе Му ( ей аг/(ей аг); 1п1/(1п1); с1азз Бсипу ( /' -. /)' патезрасе Уоиг( сйаг/(сйаг); с(оиЫе Г(с(оиЫе); с1азз 51илд(/*...*/); ) Теперь мы можем пользоваться объявлениями из Му и Уоигпри помогдн явных ква- лпфпкаторов (~ 8.2,1), из!ау-обьяелепи11 Я 8.2.2) или (~ 8.2,3) из(пд-директив. 8.2.5.1.
Неименованные пространства имен Иногда полезно помещать объявления в пространство имен просто ради того, чтобы исключить возможность конфликта имен. В атом случае целью является сохранение локальности кода, а не предоставление интерфеиса пользователям. Например: Пй1с!ис(е "аеас!егп" латезрасе Мте ( т1а; ио(с(Д) ( /" ... */ ) 11у()(/*...*/) гг) 8.2. Пространства имен Так как мы не хотим, чтобы имя лясле было доступно вне локального контекста, вве- дение имени вызывает определенное неудобство, которое к тому же может привести к случа1)ному конфликту с другим именем. В этом случае мы можем ввести простран- ство имен без имени: л(пс(ийе 'йеайег.й" латеярасе ( (и( а; эо(й/))(/ ...*/) (п(д)) ) /" .. */) Ясно, гго должен существовать какой-то способ доступа к членам неименованного пространства имен извне. Следовательно, неименованное пространство имен подра- зумевает ияпщ-директиву.
Лредыдущсс объявление эквивалентно латеярасе ббпр ) (п(а; пои( Д ( /" ... / ) (п(д)) ) /'." */) ия(пд пат еярасе ббпр ' 8.2.6. Поиск имен Является скорее правилом, чем исключением, что функция с ар1ументом типа Т оп- ределяется в том же пространстве имен, что и Т. Как следствие, если функция не най- дена в контексте ее использования, осупяествляется поиск в пространствах имен ее аргументов. Например: латеярасе Слголо ) с(аяя Ва(е ) /' ... "/ ); (то! орега(ог ==)сопя(Оа(е8„сопя( я!й.:я(г(пдЦ; я(й: я(г(пя)огта()сопя()эа(ей) //спдвольпое прейс»лпвление вогй) )Спгопо.:Оа(е й, (п(() ) я(й: я(г(пд я =/отпа( Щ я(йзя(г(пд Г =/оста()й, // Слтпок)отт(() 0 от поко: в па ~ исти вийщоспш // кет люкой 4рккции/опла(() Ло сравнению с использованием явных квалифнкаторов зто правило поиска имен экономи~ время при вводе програмлсы и не приводит к «загрязнению» пространства где 333 является некоторым 'именем, уникальным для области видимости, в которой определяется пространство имен.
В частности, неименованные пространства имен в разных единицах трансляции различны. Как и предполагалось, нельзя осуществить доступ из одной единицы трансляции к члену неименованного пространства имен пз лругой единицы. 222 Глава 8. Пространства имен и исключения имен, как зто может делать ия!пп-дирекпзияа. Это правило особенно полезно в случае применения к операндам операторов (з 11.2.4) и аргументам шаблонов (э В.13.8.4), когда явная квалнфикацвя может быть очень сложной. Обратите внимание, что само пространство имен должно быть в ооластп видимости и функция должна быть объявлена до се использования. Естественно, аргументы функций могут быть нз различных пространств имен. Например: оо!д ! (С(! гоп о: Гзаге д, ягг(:.ягг!пд я( ( (Г (д==я(( П) е!ее (Т (с! == "4 августа, 7 914г ") ( !/- ) В таких случаях осуществляется сначала поиск функции в области видимости вызова (как обычно), а затем — в пространствах имен каждого аргумента (включая класс каждого аргумента и его базовые классы).
11осле этого ко всем найденным функциям применяются обычные правила разрешения перегрузки имен Я 7.4). В частности, для вызова с(==я осуществляется поиск орега!ог == в области видимости, окружающей!'(), в пространстве имен' яЫ (там определен == для я!г(пп) н в пространстве имен С!!голо. Существует оператор яЯ;.орега!ог == (), но у него нет аргумента Т)а!е, поэтому используется С(згопосорега!ог == (), который имеет такой аргумент (см. также 5 11.24).
Когда член класса вызывает функцию с некоторым именем, другие иены того же класса и его родительских классов имеют приоритет над функцпямп, найденными на основании информации о типах аргументов. Ситуация с опсраторамп иная (см. З 11.2.1, З 11. 2 4). 8.2.7. Псевдонимы пространств имен Короткие названия пространств имен могут войти в конфликт друг с другом: ,гГ короткое илт рина или поздно приведет к конузликту патеярасеА ( А.8!г!пуя! ='Григ", А: 5ггтдя2 ="Нильсен', Однако, длинные названия пространств имен непрактичны прн написании реально- го нога: патеярасе Атее(сап Те!ерйопе апд Те!еугарИ ( !! слитки.и длинное Атенсап Те!ерйопе апд Те!едгард Вгг!пуяд ="Грие; Атеисап Те!ер(зоне апг! Те!еугар(з Бгггпдя4 = "Нильсен', Эту дилемму можно решить путем создания короткого псевдонима длинного назва- ния пространства пмсн: ггз 8.2.
Пространства имен // еоснользуеяся лсеедонилалл для сокращення ален: латеярасеАТТ=Атее!сил Те!ерЬоле анд Те!еугар1с АТТ$1г!луяз = Григ", АТТ$1г1луя4 ="Нильсен'; Псевдонимы, кроме того, позволяют пользователю ссылаться на «библиотеку» и в одном единственном объявлении определять реально используемую библиотеку. Например: латеярасе116 = Гонлда1(ол НЬгагу о2г!1; Тлб-ее!я, й!Ьс$!пну я5 = Сибелиус2 Это может значительно облегчить проблему смены версии библиотеки.
Пользуясь 116 вместогоилс1айон НЬгагу о2г11, можно персйтн к версии «цЗг02»э изменив инициализацию псевдонима 1.16 и перекомптялнровав программу. Во время компиляции будут обнаружены несоответствия на уровне исходного текста. С другой стороны, злоупотребление псевдонимами может привести к некоторой путанице. 8.2.8. Объединение пространств имен Порой возникает потребность в создании интерфейса пз набора существующих ин- терфейсов. Например; латеярасеНН я!плу( с1аяя $!г!лу(/*." '/(, $1гту орега1ог» (соля! 51плуй, соля1 5!НлдЦ $!илу орега1ог+ 1соли 51г1луй, сол4 сьа1 (; оои1 1!11 (сЬаг); латеярасеНег оес1ог( 1етр!а1есс1аяя Т> с1аяя Ъес!ог( /* ... "/ ); латеярасеМу НЬ( ия1лула~леярасе Ння я!плу; икту латеярасе Нег оес!ог; ооп1ту ~с!($1г1луй( ) После этого мы можем писать программу в терминах Му 116: ооИ Я ( Му 116: $!г!лу я = "Байрон"; //Му 1!ЬкН!я я1гтук$1плу иилу латеярасе Му 1(Ь; 224 Глава 8.
Пространства имен и исключения оо!г! у (( ес1ос'-Б1г!пу>й ое( ( //- ту ~с! (ов(б3; //-. Гели имя с явным квалнфикатором (типа Му ((бс51ппЯ не объявлено в указанном пространстве имен, компилятор осуществляет поиск в пространствах !имен, упомянутых в директивах ие!пйг (например, Нье е1г!щ). Только если нам требуется определить что-нибудь, мы должны знать имя рсального пространства имен; ооа!Му !!6:уг!! (сбагс( //огиибкаг в Му Уу не обълвлегга/г(!() ( // правильно:/г!!!) объявлена в Нге мгту оо!г1 Н!и е1г!аубг!! (сбаг с( //" ) оо!бМу 86,,гпу ~сг(51г!ауйо( //правильно //огг!пурасслгатрггггггепгся как Му !!Ьсбгг!ау, пго есгпь Нге гул ау Яггпу ( В идеале, пространство имен должно: (1] выражать логически связанный набор средств; [2( препятствовать доступу пользователей к ненужным им средствам; (3( нс требовать значительных дополнительных усилий при использовании.