Разрешение имен в области видимости класса
Конечно, имена, используемые в области видимости класса, не обязаны быть именами членов класса. В процессе разрешения в этой области ведется поиск имен, объявленных и в других областях. Если имя, употребленное в области видимости класса, не разрешается именем члена класса, то компилятор ищет его в областях, включающих определение класса или члена. В этом подразделе мы покажем, как разрешаются имена, встречающиеся в области видимости класса.
Имя, использованное внутри определения класса (за исключением определений встроенных функций-членов и аргументов по умолчанию), разрешается следующим образом:
1. Просматриваются объявления членов класса, появляющиеся перед употреблением имени.
2. Если на шаге 1 разрешение не привело к успеху, то просматриваются объявления в пространстве имен перед определением класса. Напомним, что глобальная область видимости – это тоже область видимости пространства имен. (О пространствах имен речь шла в разделе 8.5.)
Например:
typedef double Money; class Account { // ... private: static Money _interestRate; static Money initInterest(); // ... |
};
Сначала компилятор ищет объявление Money в области видимости класса Account. При этом учитываются только те объявления, которые встречаются перед использованием Money. Поскольку таких объявлений нет, далее поиск ведется в глобальной области видимости. Объявление глобального typedef Money найдено, именно этот тип и используется в объявлениях _interestRate и initInterest().
Имя, встретившееся в определении функции-члена класса, разрешается следующим образом:
1. Сначала просматриваются объявления в локальных областях видимости функции-члена. (О локальных областях видимости и локальных объявлениях говорилось в разделе 8.1.)
2. Если шаг 1 не привел к успеху, то просматриваются объявления для всех членов класса.
3. Если и этого оказалось недостаточно, просматриваются объявления в пространстве имен перед определением функции-члена.
class Screen { public: // ... void setHeight( int ); private: short _height; }; int verify(int); void Screen::setHeight( int var ) { // var: относится к параметру // _height: относится к члену класса // verify: относится к глобальной функции _height = verify( var ); |
Обратите внимание, что объявление глобальной функции verify() невидимо до определения класса Screen. Однако на третьем шаге разрешения имени просматриваются объявления в областях видимости пространств имен, видимые перед определением члена, поэтому нужное объявление обнаруживается.
Имя, встретившееся в определении статического члена класса, разрешается следующим образом:
1. Просматриваются объявления всех членов класса.
2. Если шаг 1 не привел к успеху, то просматриваются объявления, расположенные в областях видимости пространств имен перед определением статического члена, а не только предшествующие определению класса.
Упражнение 13.18
Назовите те части программы, которые находятся в области видимости класса.
Упражнение 13.19
Назовите те части программы, которые находятся в области видимости класса и для которых при разрешении имен просматривается полная область (т.е. принимаются во внимание все члены, объявленные в теле класса).
Упражнение 13.20
К каким объявлениям относится имя Type при использовании в теле класса Exersise и в определении его функции-члена setVal()? (Напоминаем, что разные вхождения могут относиться к разным объявлениям.) К каким объявлениям относится имя initVal при употреблении в определении функции-члена setVal()?
typedef int Type; Type initVal(); class Exercise { public: // ... typedef double Type; Type setVal( Type ); Type initVal(); private: int val; }; Type Exercise::setVal( Type parm ) { val = parm + initVal(); |
Определение функции-члена setVal()
ошибочно. Можете ли вы сказать, почему? Внесите необходимые изменения, чтобы в классе Exercise
использовался глобальный typedef Type и глобальная функция initVal().