Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

Если некоторая сущность объявляется во вложенном пространстве имен, она скрывает объявление одноименной сущности из объемлющего пространства.

В предыдущем примере имя Type из глобальной области видимости скрыто объявлением Type в пространстве cplusplus_primer. При разрешении имени Type, упоминаемого в MatrixLib, оно будет найдено в cplusplus_primer, поэтому у функции func() параметр имеет тип int.

Аналогично сущность, объявленная в пространстве имен, скрывается одноименной сущностью из вложенной локальной области видимости. В предыдущем примере имя val из MatrixLib скрыто новым объявлением val. При разрешении имени val внутри func() будет найдено его объявление в локальной области видимости, и потому присваивание в func() относится именно к локальной переменной.

8.5.4. Определение члена пространства имен

Мы видели, что определение члена пространства имен может появиться внутри определения самого пространства. Например, класс matrix и константа pi появляются внутри вложенного пространства имен MatrixLib, а определения функций operator+()

// ---- 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 & ); // ...

}

и inverse() приводятся где-то в другом месте текста программы:

}

Член пространства имен можно определить и вне соответствующего пространства. В таком случае имя члена должно быть квалифицировано именами пространств, к которым он принадлежит. Например, если определение функции operator+() помещено в

//---- primer.C ----

#include "primer.h"

//определение в глобальной области видимости

cplusplus_primer::MatrixLib::matrix cplusplus_primer::MatrixLib::operator+

( const matrix& ml, const matrix &m2 )

глобальную область видимости, то оно должно выглядеть следующим образом:

{ /* ... */ }

Имя operator+() квалифицировано в данном случае именами пространств cplusplus_primer и MatrixLib. Однако обратите внимание на тип matrix в списке

параметров operator+(): употреблено неквалифицированное имя. Как такое может быть?

В определении функции operator+() можно использовать неквалифицированные имена для членов своего пространства, поскольку определение принадлежит к его области видимости. При разрешении имен внутри функции operator+() используется MatrixLib. Заметим, однако, что в типе возвращаемого значения все же нужно указывать квалифицированное имя, поскольку он расположен вне области видимости, заданной определением функции:

cplusplus_primer::MatrixLib::operator+

В определении operator+() неквалифицированные имена могут встречаться в любом объявлении или выражении внутри списка параметров или тела функции. Например,

// ---- primer.C ----

#include "primer.h"

cplusplus_primer::MatrixLib::matrix cplusplus_primer::MatrixLib::operator+

( const matrix &ml, const matrix &m2 )

{

//объявление локальной переменной типа

//cplusplus_primer::MatrixLib::matrix matrix res;

//вычислим сумму двух объектов matrix return res;

локальное объявление внутри operator+() способно создать объект класса matrix:

}

Хотя члены могут быть определены вне своего пространства имен, такие определения допустимы не в любом месте. Их разрешается помещать только в пространства, объемлющие данное. Например, определение operator+() может появиться в глобальной области видимости, в пространстве имен cplusplus_primer и в

// ---- primer.C -- #include "primer.h"

namespace cplusplus_primer { MatrixLib::matrix MatrixLib::operator+

(const matrix &ml, const matrix &m2 ) { /* ...

*/ }

пространстве MatrixLib. В последнем случае это выглядит так:

}

Член может определяться вне своего пространства только при условии, что ранее он был объявлен внутри. Последнее приведенное определение operator+() было бы ошибочным, если бы ему не предшествовало объявление в файле primer.h:

namespace cplusplus_primer { namespace MatrixLib {

class matrix { /*...*/ };

//следующее объявление не может быть пропущено matrix operator+ ( const matrix &ml, const matrix

&m2 );

//...

}

}

8.5.5. ПОО и члены пространства имен

Как уже было сказано, определение пространства имен может состоять из разрозненных частей и размещаться в разных файлах. Следовательно, член пространства разрешено

// primer.h

namespace 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;

}

// ---- primer.C ----

#include "primer.h"

namespace cplusplus_primer { // определения функций void inverse( matrix & )

{ /* ... */ }

matrix operator+ ( const matrix &ml, const matrix &m2

)

{/" ... */ }

//определения объектов bool error_state = false;

1.Определения этих членов помещают в исходный файл, содержащий реализацию:

}

Для объявления объекта без его определения используется ключевое слово 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, где содержится описание интерфейса библиотеки сортировки, она объявлена в глобальной области видимости. Следовательно, это имя является глобальным, при этом сохраняется возможность конфликта с другими именами.

Язык С++ предоставляет возможность использования безымянного пространства имен

для объявления сущности, локальной по отношению к файлу. Определение такого пространства начинается ключевым словом namespace. Очевидно, что никакого имени за этим словом нет, а сразу же идет блок в фигурных скобках, содержащий различные

// ----- SortLib.C -----

namespace {

void swap( double *dl, double *d2 ) { /* ...

*/ }

}

объявления. Например:

// определения функций сортировки не изменяются

Функция swap() видна только в файле SortLib.C. Если в другом файле в безымянном пространстве имен содержится определение swap(), то это другая функция. Наличие двух функций swap() не является ошибкой, поскольку они различны. Безымянные пространства имен отличаются от прочих: определение такого пространства локально для одного файла и не может размещаться в нескольких.

Имя swap() может употребляться в неквалифицированной форме в файле SortLib.C после определения безымянного пространства. Оператор разрешения области видимости

void quickSort( double *d1, double *d2 ) { // ...

double* elem = d1;

//...

//ссылка на член безымянного пространства имен swap()

swap( d1, elem );

// ...

для ссылки на его члены не нужен.

}