С++ для начинающих


Разрешение имен в области видимости класса


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

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

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().


Содержание раздела