Когда класс расположен в пространстве имен, процесс поиска остается обычным: когда имя используется функцией-членом, его поиск начинается в самой функции, затем в пределах класса (включающий базовые классы), а потом в окружающих областях видимости, одной или несколькими из которых могли бы быть пространства имен:
namespace A {
int i;
int k;
class C1 {
public:
C1(): i(0), j(0) { } //
int f1() { return k; } //
int f2() { return h; } //
int f3();
private:
int i; //
int j;
};
int h = i; //
}
//
int A::C1::f3() { return h; } //
За исключением определений функций-членов, расположенных в теле класса (см. раздел 7.4.1), области видимости всегда просматриваются снизу вверх: имя должно быть объявлено прежде его применения. Следовательно, оператор return
функции f2()
не будет откомпилирован. Он попытается обратиться к имени h
из пространства имен А
, но там оно еще не определено. Если бы это имя h
было определено в пространстве имен А
прежде определения класса C1
, его использование было бы вполне допустимо. Аналогично использование имени h
в функции f3()
вполне допустимо, поскольку функция f3()
определена уже после определения А::h
.
Спецификаторы A::C1::f3()
указывают обратный порядок, в котором просматриваются области видимости класса и пространств имен. Первая область видимости — это функция f3()
. Далее следует область видимости ее класса C1
. Область видимости пространства имен А
просматривается в последнюю очередь, перед переходом к области видимости, содержащей определение функции f3()
.
Рассмотрим простую программу:
std::string s;
std::cin >> s;
Как известно, этот вызов эквивалентен следующему (см. раздел 14.1):
operator>>(std::cin, s);
Функция operator>>
определена библиотекой string
, которая в свою очередь определяется в пространстве имен std
. Но все же оператор >>
можно вызвать без спецификатора std::
и без объявления using
.
Непосредственно обратиться к оператору вывода можно потому, что есть важное исключение из правила сокрытия имен, определенных в пространстве имен. Когда объект класса передается функции, компилятор ищет пространство имен, в котором определяется класс аргумента
В этом примере, когда компилятор встречает "вызов" оператора operator>>
, он ищет соответствующую функцию в текущей области видимости, включая области видимости, окружающие оператор вывода. Кроме того, поскольку выражение вывода имеет параметры типа класса, компилятор ищет также в пространствах имен, в которых определяются типы cin
и s
. Таким образом, для этого вызова компилятор просмотрит пространство имен std
, определяющее типы istream
и string
. При поиске в пространстве имен std
компилятор находит функцию вывода класса string
.
Это исключение из правил поиска позволяет функции, не являющейся членом класса, быть концептуально частью интерфейса к классу и использоваться без отдельного объявления using
. Без этого исключения из правил поиска для оператора вывода всегда пришлось бы предоставлять соответствующее объявление using
:
using std::operator>>; //
Либо пришлось бы использовать форму записи вызова функции, включающую спецификатор пространства имен:
std::operator>>(std::cin, s); //
He было бы никакого способа использовать синтаксис оператора. Любое из этих объявлений выглядит неуклюже и существенно затруднило бы использование библиотеки ввода-вывода.
std::move()
и std::forward()