Выбрать главу

В главе 11 был приведен пример программы, использующей класс iStack. Измените его, объявив классы исключений pushOnFull и popOnEmpty открытыми вложенными в iStack. Модифицируйте соответствующим образом определение класса iStack и его функций-членов, а также определение main().

13.11. Классы как члены пространства имен A

Представленные до сих пор классы определены в области видимости глобального пространства имен. Но их можно определять и в объявленных пользователем пространствах. Имя класса, определенного таким образом, доступно только в области видимости этого пространства, т.е. оно не конфликтует с именами, объявленными в других пространствах имен. Например:

namespace cplusplus_primer {

class Node { /* ... */ };

}

namespace DisneyFeatureAnimation {

class Node { /* ... */ };

}

Node *pnode; // ошибка: Node не видно в глобальной области видимости

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

// квалифицированного типа DisneyFeatureAnimation::Node

DisneyFeatureAnimation::Node nodeObj;

// using-объявление делает Node видимым в глобальной области видимости

using cplusplus_primer::Node;

Node another; // cplusplus_primer::Node

Как было показано в двух предыдущих разделах, член класса (функция-член, статический член или вложенный класс) может быть определен вне его тела. Если мы реализуем библиотеку и помещаем определения наших классов в объявленное пользователем пространство имен, то где расположить определения членов, находящиеся вне тел своих классов? Их можно разместить либо в пространстве имен, которое содержит определение самого внешнего класса, либо в одном из объемлющих его пространств. Это дает возможность организовать код библиотеки следующим образом:

// --- primer.h ---

namespace cplusplus_primer {

class List {

// ...

private:

class ListItem {

public:

void check_status();

int action();

// ...

};

};

}

// --- primer.C ---

#include "primer.h"

namespace cplusplus_primer {

// правильно: check_status() определено в том же пространстве имен,

// что и List

void List::ListItem::check_status() { }

}

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

// в пространстве имен, объемлющем определение класса List

// Имя члена квалифицировано именем пространства

int cplusplus_primer::List::ListItem::action() { }

Члены вложенного класса ListItem можно определить в пространстве имен cplusplus_primer, которое содержит определение List, или в глобальном пространстве, включающем определение cplusplus_primer. В любом случае имя члена в определении должно быть квалифицировано именами объемлющих классов и объявленных пользователем пространств, вне которых находится объявление члена.

Как происходит разрешение имени в определении члена, которое находится в объявленном пользователем пространстве? Например, как будет разрешено someVaclass="underline"

int cplusplus_primer::List::ListItem::action() {

int local = someVal;

// ...

}

Сначала просматриваются локальные области видимости в определении функции-члена, затем поиск продолжается в области видимости ListItem, затем – в области видимости List. До этого момента все происходит так же, как в процессе разрешения имен, описанном в разделе 13.10. Далее просматриваются объявления из пространства cplusplus_primer и наконец объявления в глобальной области видимости, причем во внимание принимаются только те, которые расположены до определения функции-члена action():

// --- primer.h ---

namespace cplusplus_primer {

class List {

// ...

private:

class ListItem {

public:

int action();

// ...

};

};

const int someVal = 365;

}

// --- primer.C ---

#include "primer.h"

namespace cplusplus_primer {

int List::ListItem::action() {

// правильно: cplusplus_primer::someVal

int local = someVal;

// ошибка: calc() еще не объявлена

double result = calc( local );

// ...

}

double calc(int) { }

// ...

}

Определение пространства имен cplusplus_primer не является непрерывным. Определения класса List и объекта someVal размещены в первом его разделе, который находится в заголовочном файле primer.h. Определение функции calc() появляется в определении пространства имен, расположенном в файле реализации primer.C. Использование calc() внутри action() ошибочно, так как она объявлена после использования. Если calc() – часть интерфейса cplusplus_primer, ее следовало бы объявить в той части данного пространства, которая находится в заголовочном файле: