С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 68
Текст из файла (страница 68)
*/ };class Raccoon : public Bear { /* ... */ };// ...}}Пространство имен cplusplus_primer содержит два вложенных: MatrixLib иAnimalLib.cplusplus_primer предотвращает конфликт между именами из нашей библиотеки иименами из глобального пространства вызывающей программы. Вложенность позволяетделить библиотеку на части, в которых сгруппированы связанные друг с другомобъявления и определения. MatrixLib содержит сущности, имеющие отношение к классуmatrix, а AnimalLib – к классу ZooAnimal.Объявление члена вложенного пространства скрыто в этом пространстве. Имя такогочлена автоматически дополняется поставленными спереди именами самого внешнего ивложенного пространств.Например, класс, объявленный во вложенном пространстве MatrixLib, имеет имяcplusplus_primer::MatrixLib::matrixа функцияcplusplus_primer::MatrixLib::inverseПрограмма,использующаячленывложенного#include "primer.h"// да, это ужасно...// скоро мы рассмотрим механизмы, облегчающие// использование членов пространств имен!void func( cplusplus_primer::MatrixLib::matrix &m ){// ...cplusplus_primer::MatrixLib::inverse( m );return m;cplusplus_primer::MatrixLib, выглядит так:пространстваС++ для начинающих}Вложенное пространство имен является вложенной областью видимости внутрипространства, содержащего его.
В процессе разрешения имен вложенные пространстваведут себя так же, как вложенные блоки. Когда некоторое имя употребляется впространстве имен, поиск его объявление проводится во всех объемлющихпространствах. В следующем примере разрешение имени Type происходит в такомпорядке: сначала ищем его в пространстве имен MatrixLib, затем в cplusplus_primer иtypedef double Type;namespace cplusplus_primer {typedef int Type; // скрывает ::Typenamespace MatrixLib {int val;// Type: объявление найдено в cplusplus_primerint func(Type t) {double val; // скрывает MatrixLib::valval = ...;}// ...}наконец в глобальной области видимости:}Если некоторая сущность объявляется во вложенном пространстве имен, она скрываетобъявление одноименной сущности из объемлющего пространства.В предыдущем примере имя Type из глобальной области видимости скрыто объявлениемType в пространстве cplusplus_primer.
При разрешении имени Type, упоминаемого вMatrixLib, оно будет найдено в cplusplus_primer, поэтому у функции func()параметр имеет тип int.Аналогично сущность, объявленная в пространстве имен, скрывается одноименнойсущностью из вложенной локальной области видимости. В предыдущем примере имя valиз MatrixLib скрыто новым объявлением val. При разрешении имени val внутриfunc() будет найдено его объявление в локальной области видимости, и потомуприсваивание в func() относится именно к локальной переменной.8.5.4. Определение члена пространства именМы видели, что определение члена пространства имен может появиться внутриопределения самого пространства. Например, класс matrix и константа pi появляютсявнутри вложенного пространства имен MatrixLib, а определения функций operator+()и inverse() приводятся где-то в другом месте текста программы:407С++ для начинающих// ---- primer.h ---namespace cplusplus_primer {// первое вложенное пространство имен:// матричная часть библиотекиnamespace MatrixLib {class matrix { /* ...
*/ };const double pi = 3.1416;matrix operators+ ( const matrix &ml, const matrix &m2 );void inverse( matrix & );// ...}}Член пространства имен можно определить и вне соответствующего пространства. Втаком случае имя члена должно быть квалифицировано именами пространств, к которымон принадлежит.
Например, если определение функции operator+() помещено в// ---- primer.C ---#include "primer.h"// определение в глобальной области видимостиcplusplus_primer::MatrixLib::matrixcplusplus_primer::MatrixLib::operator+( const matrix& ml, const matrix &m2 )глобальную область видимости, то оно должно выглядеть следующим образом:{ /* ... */ }Имя operator+() квалифицировано в данном случае именами пространствcplusplus_primer и MatrixLib. Однако обратите внимание на тип matrix в спискепараметров operator+(): употреблено неквалифицированное имя.
Как такое можетбыть?В определении функции operator+() можно использовать неквалифицированные именадля членов своего пространства, поскольку определение принадлежит к его областивидимости. При разрешении имен внутри функции operator+() используетсяMatrixLib. Заметим, однако, что в типе возвращаемого значения все же нужно указыватьквалифицированное имя, поскольку он расположен вне области видимости, заданнойопределением функции:cplusplus_primer::MatrixLib::operator+В определении operator+() неквалифицированные имена могут встречаться в любомобъявлении или выражении внутри списка параметров или тела функции.
Например,локальное объявление внутри operator+() способно создать объект класса matrix:408С++ для начинающих// ---- primer.C ---#include "primer.h"cplusplus_primer::MatrixLib::matrixcplusplus_primer::MatrixLib::operator+( const matrix &ml, const matrix &m2 ){// объявление локальной переменной типа// cplusplus_primer::MatrixLib::matrixmatrix res;// вычислим сумму двух объектов matrixreturn res;}Хотя члены могут быть определены вне своего пространства имен, такие определениядопустимы не в любом месте. Их разрешается помещать только в пространства,объемлющие данное.
Например, определение operator+() может появиться вглобальной области видимости, в пространстве имен cplusplus_primer и в// ---- primer.C -#include "primer.h"namespace cplusplus_primer {MatrixLib::matrix MatrixLib::operator+( const matrix &ml, const matrix &m2 ) { /* ... */ }пространстве MatrixLib. В последнем случае это выглядит так:}Член может определяться вне своего пространства только при условии, что ранее он былобъявлен внутри. Последнее приведенное определение operator+() было быnamespace cplusplus_primer {namespace MatrixLib {class matrix { /*...*/ };// следующее объявление не может быть пропущеноmatrix operator+ ( const matrix &ml, const matrix &m2 );// ...}ошибочным, если бы ему не предшествовало объявление в файле primer.h:}8.5.5.
ПОО и члены пространства именКак уже было сказано, определение пространства имен может состоять из разрозненныхчастей и размещаться в разных файлах. Следовательно, член пространства разрешенообъявлять во многих файлах. Например:409С++ для начинающих// primer.hnamespace cplusplus_primer {// ...void inverse( matrix & );}// usel.C#include "primer.h"// объявление cplusplus_primer::inverse() в use1.C// use2.C#include "primer.h"// объявление cplusplus_primer::inverse() в use2.CОбъявление cplusplus::inverse() в primer.h ссылается на одну и ту же функцию вобоих исходных файлах use1.C и use2.C.Член пространства имен является глобальной сущностью, хотя его имяквалифицировано.
Требование ПОО (правило одного определения, см. раздел 8.2)распространяется и на него. Чтобы удовлетворить этому требованию, программы, вкоторых используются пространства имен, обычно организуют следующим образом:1. Объявления функций и объектов, являющихся членами пространства имен,помещают в заголовочный файл, который включается в каждый исходный файл, где// ---- primer.h ---namespace cplusplus_primer {class matrix { /* ...
*/ };// объявления функцийextern matrix operator+ ( const matrix &m1, const matrix &m2 );extern void inverse( matrix & );// объявления объектовextern bool error_state;они используются.}2. Определения этих членов помещают в исходный файл, содержащий реализацию:410С++ для начинающих411// ---- primer.C ---#include "primer.h"namespace cplusplus_primer {// определения функцийvoid inverse( matrix & ){ /* ... */ }matrix operator+ ( const matrix &ml, const{ /" ... */ }matrix &m2)// определения объектовbool error_state = false;}Для объявления объекта без его определения используется ключевое слово extern, как ив случае такого объявления в глобальной области видимости.8.5.6.
Безымянные пространства именМожет возникнуть необходимость определить объект, функцию, класс или любуюдругую сущность так, чтобы она была видимой только в небольшом участке программы.Это еще один способ решения проблемы засорения глобального пространства имен.Поскольку мы уверены, что эта сущность используется ограниченно, можно не тратитьвремя на выдумывание уникального имени. Если мы объявляем объект внутри функцииили блока, его имя видимо только в этом блоке. А как сделать некоторую сущностьдоступной нескольким функциям, но не всей программе?Предположим, мы хотим реализовать набор функций для сортировки вектора типа// ----- SortLib.h ----void quickSort( double *, double * );void bubbleSort( double *, double * );void mergeSort( double *, double * );double:void heapSort( double *, double * );Все они используют одну и ту же функцию swap() для того, чтобы менять местамиэлементы вектора.
Однако она не должна быть видна во всей программе, посколькунужна только четырем названным функциям. Локализуем ее в файле SortLib.C.// ----- SortLib.C ----void swap( double *dl, double *d2 ) { /* ... */ }// только эти функции используют swap()void quickSort( double *d1, double *d2 ) { /* ... */ }void bubbleSort( double *d1, double *d2 ) { /* ... */ }void mergeSort( double *d1, double *d2 ) { /* ... */ }Приведенный код не дает желаемого результата. Как вы думаете, почему?void heapSort( double *d1, double *d2 ) { /* ... */ }С++ для начинающихХотя функция swap() определена в файле SortLib.C и не появляется в заголовочномфайле SortLib.h, где содержится описание интерфейса библиотеки сортировки, онаобъявлена в глобальной области видимости. Следовательно, это имя являетсяглобальным, при этом сохраняется возможность конфликта с другими именами.Язык С++ предоставляет возможность использования безымянного пространства имендля объявления сущности, локальной по отношению к файлу.