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

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

#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"!;

}

использовать оператор разрешения области видимости ::max. Вот текст программы:

}

Так выглядит функция main(), вызывающая fibonacci():

#include <iostream> void fibonacci( int ); int main() {

cout << "Числа Фибоначчи: 16\n";

fibonacci( 16 ); return 0;

}

Результат работы программы:

 

Числа

Фибоначчи:

16

34

55

89

 

 

 

 

0

1

1

2

3 5

8

13

21

 

 

144

233

377

610

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

8.5.3. Вложенные пространства имен

Мы уже упоминали, что пользовательские пространства имен могут быть вложенными. Такие пространства применяются для дальнейшего структурирования кода нашей

// ---- 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 { /* ... */ }; 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; // скрывает ::Type

namespace MatrixLib { int val;

// Type: объявление найдено в cplusplus_primer

int func(Type t) {

double val; // скрывает MatrixLib::val val = ...;

}

// ...

}

наконец в глобальной области видимости:

}