С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 67
Текст из файла (страница 67)
Поэтому существуют механизмы, позволяющие облегчить использованиепространств имен в программах. Это псевдонимы пространств имен, using-объявления иusing-директивы. (Мы рассмотрим их в разделе 8.6.)400С++ для начинающих8.5.1. Определения пространства именОпределение пользовательского пространства имен начинается с ключевого словаnamespace, за которым следует идентификатор. Он должен быть уникальным в тойобласти видимости, в которой определяется данное пространство; наличие другойсущности с тем же именем является ошибкой. Конечно, это не означает, что проблемазасорения глобального пространства решена полностью, но существенно помогает в еерешении.За идентификатором пространства имен следует блок в фигурных скобках, содержащийразличные объявления. Любое объявление, допустимое в области видимости глобальногопространства, может встречаться и в пользовательском: классы, переменные (вместе синициализацией), функции (вместе со своими определениями), шаблоны.Помещая объявление в пользовательское пространство, мы не меняем его семантики.Единственное отличие состоит в том, что имена, вводимые такими объявлениями,namespace cplusplus_primer {class matrix { /* ...
*/ };void inverse ( matrix & );matrix operator+ ( const matrix &ml, const matrix &m2 ){/* ... */ }const double pi = 3.1416;включают в себя имя пространства, внутри которого они объявлены. Например:}Именем класса, объявленного в пространстве cplusplus_primer, будетcplusplus_primer::matrixИменем функцииcplusplus_primer::inverse()Именем константыcplusplus_primer::piИмя класса, функции или константы расширяется именем пространства, в котором ониобъявлены. Такие имена называют квалифицированными.Определение пространства имен не обязательно должно быть непрерывным.
Например,предыдущее пространство могло быть определено таким образом:401С++ для начинающих402namespace cplusplus_primer {class matrix { /* ... */ };const double pi = 3.1416;}namespace cplusplus_primer {void inverse ( matrix & );matrix operator+ ( const matrix &ml, const matrix &m2 ){/* ... */ }}Два приведенных примера эквивалентны: оба задают пространство именcplusplus_primer, содержащее класс matrix, функцию inverse(), константу pi иoperator+(). Определение пространства имен может состоять из несколькихсоединенных частей.Последовательностьnamespace namespace_name {задает новое пространство, если имя namespace_name не совпадает с одним из ранееобъявленных.
В противном случае новые объявления добавляются в старое пространство.Возможность разбить пространство имен на несколько частей помогает при организациибиблиотеки. Ее исходный код легко разделить на интерфейсную часть и реализацию.// Эта часть пространства имен// определяет интерфейс библиотекиnamespace cplusplus_primer {class matrix { /* ... */ };const double pi = 3.1416;matrix operator+ ( const matrix &ml,void inverse ( matrix & );}const matrix &m2);// Эта часть пространства имен// определяет реализацию библиотекиnamespace cplusplus_primer {void inverse ( matrix &m ){ /* ...
*/ }matrix operator+ ( const matrix &ml,{ /* ... */ }const matrix &m2 )Например:}Первая часть пространства имен содержит объявления и определения, служащиеинтерфейсом библиотеки: определения типов, констант, объявления функций. Во второйчасти находятся детали реализации, то есть определения функций.Еще более полезной для организации исходного кода библиотеки является возможностьразделить определение одного пространства имен на несколько файлов: эти определениятакже объединяются.
Наша библиотека может быть устроена следующим образом:С++ для начинающих403// ---- primer.h ---namespace cplusplus_primer {class matrix { /*... */ };const double pi = 3.1416;matrix operator+ ( const matrix &m1, const matrix &m2 );void inverse( matrix & );}// ---- primer.C ---#include "primer.h"namespace cplusplus_primer {void inverse( matrix &m ){ /* ... */ }matrix operator+ ( const matrix &m1, const matrix &m2 ){ /* ... */ }}// ---- user.C ---// определение интерфейса библиотеки#include "primer.h"void func( cplusplus_primer::matrix &m{//...cplusplus_primer: :inverse( m );return m;)Программа, использующая эту библиотеку, выглядит так:}Подобная организация программы обеспечивает модульность библиотеки, необходимуюдля сокрытия реализации от пользователей, в то же время позволяя без ошибокскомпилировать и связать файлы primer.C и user.C в одну программу.8.5.2.
Оператор разрешения области видимостиИмя члена пользовательского пространства дополняется поставленным спереди именемэтого пространства и оператором разрешения области видимости (::). Использованиенеквалифицированного члена, например matrix, является ошибкой.
Компилятор не// определение интерфейса библиотеки#include "primer.h"// ошибка: нет объявления для matrixзнает, к какому объявлению относится это имя:void func( matrix &m );Объявление члена пространства имен скрыто в своем пространстве. Если мы не укажемкомпилятору, где именно искать объявление, он произведет поиск только в текущейобласти видимости и в областях, включающих текущую. Допустим, если переписатьпредыдущую программу так:С++ для начинающих// определение интерфейса библиотеки#include "primer.h"class matrix { /* пользовательское определение */ };// правильно: глобальный тип matrix найденvoid func( matrix &m );то определение класса matrix компилятор находит в глобальной области видимости ипрограмма компилируется без ошибок.
Поскольку объявление matrix как членапространства имен cplusplus_primer скрыто в этом пространстве, оно не конфликтует склассом, объявленным в глобальной области видимости.Именно поэтому мы говорим, что пространства имен решают проблему засоренияглобального пространства: имена их членов невидимы, если имя пространства не указаноявно, с помощью оператора разрешения области видимости. Существуют и другиемеханизмы, позволяющие сделать объявление члена пространства имен видимым вне его.Это using-объявления и using-директивы. Мы рассмотрим их в следующем разделе.Отметим, что оператор области видимости может быть использован и для того, чтобысослаться на элемент глобального пространства имен. Поскольку это пространство неимеет имени, запись::member_nameотносится к его элементу. Такой способ полезен для указания членов глобальногопространства, если их имена оказываются скрыты именами, объявленными вовложенных локальных областях видимости.Следующий пример демонстрирует использование оператора области видимости дляобращения к скрытому члену глобального пространства имен.
Функция вычисляетпоследовательность чисел Фибоначчи. В программе два определения переменной max.Глобальная переменная указывает максимальное значение элемента последовательности,при превышении которого вычисление прекращается, а локальная – желаемую длинупоследовательности при данном вызове функции. (Напоминаем, что параметры функцииотносятся к ее локальной области видимости.) Внутри функции должны быть доступныобе переменных. Однако неквалифицированное имя max ссылается на локальноеобъявление этой переменной.
Чтобы получить глобальную переменную, нужноиспользовать оператор разрешения области видимости ::max. Вот текст программы:404С++ для начинающих#include <iostream>const int max = 65000;const int lineLength = 12;void fibonacci( int max ){if ( max < 2 ) return;cout << "0 1 ";int v1 = 0, v2 = 1, cur;for ( int ix = 3; ix <= max; ++ix ) {cur = v1 + v2;if ( cur > ::max ) break;cout << cur << " ";vl = v2;v2 = cur;if (ix % "lineLength == 0) cout << end"!;}}#include <iostream>void fibonacci( int );int main() {cout << "Числа Фибоначчи: 16\n";fibonacci( 16 );return 0;Так выглядит функция main(), вызывающая fibonacci():}Результат работы программы:Числа Фибоначчи: 160 1 1 2 3 5 8 13 21 34 55 89144 233 377 6108.5.3.
Вложенные пространства именМы уже упоминали, что пользовательские пространства имен могут быть вложенными.Такие пространства применяются для дальнейшего структурирования кода нашейбиблиотеки. Например:405С++ для начинающих406// ---- 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 & );// ...}// второе вложенное пространство имен:// зоологическая часть библиотекиnamespace AnimalLib {class ZooAnimal { /* ... */ };class Bear : public ZooAnimal { /* ...