Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 50
Текст из файла (страница 50)
Пространства имен 8.2.8.2. Композиция пространств имен и отбор элементов Если объединить композицию пространств имен (при помощи директив ия!лИ) с отбором элементов (при помощи объявлений ия!пИ), то будет получена гибкость, достаточная для решения большинства реальных задач. С помощью этих механизмов мы можем обеспечить доступ к определенному набору средств таким образом, чтобы надежно избегать при этом конфликта имен и неоднозначностей. Например; латеярасе НЭ ИЬ ( с(ат Лягте ( /* ... */ ); гетр!иге<с!ам Т> с1аяя ) есюог( /* ... */ ); /У... ) патеярасе Нег ИЬ юетрюаюе<сюам Т> с!вяз Кесюог ( /* ... */ ); с!ам Яюг(ля ( /* ...
*/ ); У... ) патеярасе Му ИЬ ( июйлд патеярасе НИ ИЬ ю иялл патеярасе Нег ИЬю /У все из НИ Июь /У все из Нег 1й ия(па НИ 1юЬ:: Яюг(пе; И разрешается в пользу НЭ ИЬ пята Нег ИЬ ю: 1'есме ! дразрешается в пользу Нег 1й юетрюаюе<сюат Т> с(аяя 181 ( /* ... */ ) ю //прочее И.„ патеярасе 1.1Ь2 ия(ла патеярасе Н(з ИЬ! итиля патеярасе Нег ИЬ ! У все из НИ (й Ивсе из Нег ИЬ д разрешается в пользу Н1я ИЬ //разрешается в пользу Нег !й ия(ли Н(я ИЬ:: Яюг(па; ия(па Нег ИЬ:: Иесюог; И переименовываем юурею(е(Нег ИЬю:Бюг(ла Нег я!гюля! Имена, объявленные явно в пространстве имен (включая те, что присутствуют в составе объявлений вю)иИ) имеют приоритет над именами, внесенными с помощью директив ия(пд (см, также 5С.(0.1).
Следовательно, пользователь Му ИЬ обнаружит, что конфликты имен БитВ и Гесиюг разрешаются в пользу Ни 1юЬ:: Лития и Нег 1юЬ:: Кесюг. Также по умолчанию получает приоритет Му ИЬ:: Т1яю, независимо от того, объявляется ли в Нюя 1юЬ или Нег ИЬ класс АН1 или нет. Обычно, я предпочитаю не менять имя при включении его в новое пространство имен. В результате мне не нужно помнить два разных имени для одного и того же элемента. Тем не менее, иногда нужно или удобно ввести новое имя. Например: 238 Глава 8. Пространства имен и исключения // "Переименовываем ": !етр1а(е<с1аве Т> с!аев Н!в »ее: риЫ!с Нтв 11Ь:: Уес!ое<Т>( /* ...
*/ ); !етр!а!е<с)авв Т> с!аве ЕЫ ( /* ... */ ); //прочее // ... ) В языке нет специальных средств для переименования. Приходится использовать стандартные механизмы определения новых сущностей. 8.2.9. Пространства имен и старый код Миллионы строк кода на С и С++ используют глобальные имена и ранние версии библиотек.
Как применить пространства имен, чтобы смягчить проистекающие из-за этого проблемы? Переписать существующий код возможно далеко не всегда, но к счастью, библиотеками языка С можно пользоваться так, как будто они определены в пространствах имен. С библиотеками С++ такой номер не проходит (59.2.4), но пространства имен разработаны таким образом, что их можно было почти что безболезненно добавлять в существующий код на языке С++. 8.2.9.1. Пространства имен и язык С Рассмотрим каноническую начальную программу на С: ()!лс(иае <в!а(о. Ь> !л! та(п () ( рнпг1 ("Нейо, нюгЫ! ~п" ) Вряд ли хорошей идеей будет явная переработка этой программы, так же как и разработка специальных версий стандартных библиотек.
Поэтому правила языка для пространств имен разработаны таким образом, что можно относительно легко превратить старый код, не использующий пространств имен, в более структурированную версию, опирающуюся на пространства имен (наша программа калькулятор (56.1) в целом демонстрирует этот подход). В качестве одного из способов решения этой задачи, поместим объявления из старых версий файла згйо. Ь в пространство имен заб // файл св!а!о: патеврасе в!а !п! рпл(Г(соле! сьас* ... ); //... ) При наличии файла <сзй!1о>, можно обеспечить обратную совместимость, если в новый заголовочный файл <зг!!!о. Ь> поместить следующий код: //файл вййо.Ьн Иле!иле <смита> пиля пате»расе вта'! Этот вариант файла <ей!1о. Ь>, опирающийся на директиву ие!пя, позволяет успешно скомпилировать Старый вариант программы «НеБо, вот!Й», К сожалению, 239 8.2.
Пространства имен директива из1пя вносит в глобальную область видимости вообще все имена из про- странства имен зЫ. Например; () 1псгиае < «есго«> «есгог «1) ИпсгиИе <вот(о. Й> «естог «2; Поэтому в файле <ж11о. В> лучше применить обьявления ат1пВ, вносящие в глобальную область видимости лишь элементы, определенные в файле <сзгйо>: УУ файл зЫ(о.Ь: () 1пс1иае <сзЫ(о> изгое згй:: р«1п(Г« уу ... Еше одно преимушество состоит в том, что объявление из1пя предотвращает (случайное или намеренное) определение пользователем нестандартных версий функции рппаГ() в глобальной области видимости.
Вообще, я рассматриваю нелокальные директивы ив1пВ лишь как переходное средство. В большинстве случаев код в программах, ссылающихся на имена из других пространств имен, лучше выражается при помощи явных квалификаторов и объявлений аз1пВ. Связь между пространствами имен и компоновкой рассматривается в 59.2.4.
8.2.9.2. Пространства имен и перегрузка Перегрузка (57.4) работает поверх пространств имен. Это существенный момент, помогающий мигрировать от старых версий библиотек к применению пространств имен с минимальными изменениями исходного кода. Например: УУ старый А.Ь: «оЫГ(тт) « уу ... УУ старый В.й: «оЫ г"(айаг); р... Устарый изег.с: Ыпсгиь(е «А .
Л « ()тс1ийе «В. й" юЫя() ( .«('а') ' ! УУ вызываетсяЯ из В.п Э)у программу можно переработать в версию с пространствами имен без изменения содержательной части кода: УУ новый А.й: патезрасе А ( юЫг (йи); УУ избегаем загрязнения глобального пространства ,У еггог: нет "«ес(ог" в глобальной области видимости УУ содержит "илпл патеэрасе зМ;" УУ оорз: теперь это работает 24(з Глава 8. Пространства имен и исключения // новый В.)и патезрасе В ( го1й )'(сааг) // ... ) // новый изег.с. ()1пс1иае пА .
л" Ппс1иде чВ. йч из(ле патезрасе А; из(ле латезрасе В; юЫе() ( 1'( 'а' ); ) //вызывается/() из В.п Если бы мы хотели оставить файл ияег. с вообше без изменений, то в таком случае можно было бы поместить директивы ив(лВ в заголовочные файлы. 8.2.9.3. Пространства имен открыты Пространства имен открыты — это означает, что в них можно добавлять имена в пределах нескольких объявлений одного и того же пространства имен: патезрасе А ( 1пт)'(); ) // в А присутствует )() латезрасе А ( 1л1 е(); ) //в А присутствуют~() и й() //мой заголовочный файл: юЫ1'() з //моя функция //... ()1пс1ийе <зййо.п> 1лтя(); /моя функция // ...
может быть переписан без изменения порядка объявлений: Отсюда следует, что мы можем реализовывать большие программные фрагменты в рамках одного и того же пространства имен точно так же, как ранее разрабатывались приложения и библиотеки в рамках единственного глобального пространства.
Для этого нужно распределить определение пространства имен по нескольким заголовочным файлам н файлам с исходным кодом. Как показано в примере программы калькулятора (48.2,4), открытость пространств имен позволяет предоставлять разные интерфейсы разным группам пользователей, открывая для них разные части пространства имен. Открытость также помогает при переходе от старого кода к новым его вариантам. Например, следующий код 8 3 Исключения 241 //мой заголовочный файл: папзеврасе М1пе коЫ/'() з //.. ) //моя функция Ыпс(ийе <зЫ1о.
Й> //моя функция Разрабатывая новые программы, я предпочитаю организовывать множество мелких пространств имен (58.2.8), нежели помещать большие фрагменты кода в единственное пространство имен. Однако при конвертировании ранних версий больших программ это не практично. Для определения элемента, ранее объявленного в пространстве имен, лучше использовать синтаксис М1пе::, чем повторно открывать М(пе. Например: юЫ М(пе::бг( ) ( // .. ) //еггот Я() нет в Мте Компилятор легко обнаруживает продемонстрированную ошибку. Однако ввиду того, что функции могут сразу определяться в объявлении пространства имен, компилятор не сможет обнаружить эквивалентную ошибку в случае повторного открытия М)пе: Действительно, откуда компилятору знать, что на самом деле вы не вводите новую функцию)у() .
Псевдонимы пространств имен Ц8.2.7) могут применяться для квалификации имен элементов пространства при их определении. Однако эти псевдонимы нельзя использовать для повторного открытия пространств имен, 8.3. Исключения Котла программа составляется из отдельных модулей и, особенно, когда эти модули приналлежат независимо разработанным библиотекам, обработку ошибок следует разделить на две части: патезрасе Мзпе ( ипд() з //... ) пазпезрасе Мзпе ю1йЯ'( ) ( // ...
) /'... ) // повторное открытие М(пе с целью определения функции / оорз! Я() добавляется в Мте этим определениелз 242 Глава 8. Пространства имен и исключения 1. На выдачу сообшений об условиях возникновения ошибок, локальная обработка которых невозможна. 2. На собственно обработку ошибок, обнаруженных в любых частях программы. Автор библиотеки в состоянии обнаруживать ошибки времени выполнения, но, как правило, не имеет понятия о том, что с ними делать. Пользователь библиотеки может знать, как поступать в той или иной ошибочной ситуации, но не может их обнаруживать (иначе это были бы исключительно ошибки в пользовательском коде). В примере с калькулятором мы избежали этой проблемы, создав программу в виде единого целого.
Обработка ошибок встраивалась там как часть единой системы. Но после того, как мы разнесли разные логические части калькулятора по разным пространствам имен, обнаружилось, что все пространства имен зависят от пространства имен Еггог (88.2.2), и что обработка ошибок в Еггог полагается на соответствующее поведение остальных модулей в отношении возникаюших в них ошибок.