Опубликован: 26.06.2003 | Доступ: свободный | Студентов: 36634 / 5382 | Оценка: 4.07 / 3.80 | Длительность: 15:14:00
ISBN: 978-5-9556-0017-8

Лекция 15: Определение, время жизни и области видимости переменных в больших программах

< Лекция 14 || Лекция 15: 12 || Лекция 16 >

Область видимости имен

Между именами переменных, функций, типов и т.п. при использовании одного и того же имени в разных частях программы могут возникать конфликты. Для того чтобы эти конфликты можно было разрешать, в языке существует такое понятие как область видимости имени.

Минимальной областью видимости имен является блок. Имена, определяемые в блоке, должны быть различны. При попытке объявить две переменные с одним и тем же именем произойдет ошибка. Имена, определенные в блоке, видимы (доступны) в этом блоке после описания и во всех вложенных блоках. Аргументы функции, описанные в ее заголовке, рассматриваются как определенные в теле этой функции.

Имена, объявленные в классе, видимы внутри этого класса, т.е. во всех его методах. Для того чтобы обратиться к атрибуту класса, нужно использовать операции " .", " -> " или " ::".

Для имен, объявленных вне блоков, областью видимости является весь текст файла, следующий за объявлением.

Объявление может перекрывать такое же имя, объявленное во внешней области.

int x = 7;
class A
{
public:
     void foo(int y);
     int x;
};
int main()
{
     A a;  
     a.foo(x);    
  // используется глобальная переменная x
  // и передается значение 7  
     cout << x;
     return 1;
}
void
A::foo(int y)
{  
     x = y + 1;
     {
          double x = 3.14;

          cout << x;
     }
     cout << x;
}    // x – атрибут объекта типа A
  // новая переменная x перекрывает атрибут класса x

В результате выполнения приведенной программы будет напечатано 3.14, 8 и 7.

Несмотря на то, что имя во внутренней области видимости перекрывает имя, объявленное во внешней области, перекрываемая переменная продолжает существовать. В некоторых случаях к ней можно обратиться, явно указав область видимости с помощью квалификатора " ::". Обозначение ::имя говорит о том, что имя относится к глобальной области видимости. (Попробуйте поставить :: перед переменной x в приведенном примере.) Два двоеточия часто употребляют перед именами стандартных функций библиотеки языка Си++, чтобы, во-первых, подчеркнуть, что это глобальные имена, и, во-вторых, избежать возможных конфликтов с именами методов класса, в котором они употребляются.

Если перед квалификатором поставить имя класса, то поиск имени будет производиться в указанном классе. Например, обозначение A::x показало бы, что речь идет об атрибуте класса A. Аналогично можно обращаться к атрибутам структур и объединений. Поскольку определения классов и структур могут быть вложенными, у имени может быть несколько квалификаторов:

class Example
{
public:
     enum Color { RED, WHITE, BLUE };
     struct Structure
     {
          static int Flag;
          int x;
     };
     int y;
     void Method();
};

Следующие обращения допустимы извне класса:

Example::BLUE
Example::Structure::Flag

При реализации метода Method обращения к тем же именам могут быть проще:

void
Example::Method()
{
     Color x = BLUE;
     y = Structure::Flag;
}

При попытке обратиться извне класса к атрибуту набора BLUE компилятор выдаст ошибку, поскольку имя BLUE определено только в контексте класса.

Отметим одну особенность типа enum. Его атрибуты как бы экспортируются во внешнюю область имен. Несмотря на наличие фигурных скобок, к атрибутам перечисленного типа Color не обязательно (хотя и не воспрещается) обращаться Color::BLUE.

Оператор определения контекста namespace

Несмотря на столь развитую систему областей видимости имен, иногда и ее недостаточно. В больших программах возможность возникновения конфликтов на глобальном уровне достаточно реальна. Имена всех классов верхнего уровня должны быть различны. Хорошо, если вся программа разрабатывается одним человеком. А если группой? Особенно при использовании готовых библиотек классов. Чтобы избежать конфликтов, обычно договариваются о системе имен классов. Договариваться о стиле имен всегда полезно, однако проблема остается, особенно в случае разработки классов, которыми будут пользоваться другие.

Одно из сравнительно поздних добавлений к языку Си++ – контексты, определяемые с помощью оператора namespace. Они позволяют заключить группу объявлений классов, переменных и функций в отдельный контекст со своим именем. Предположим, мы разработали набор классов для вычисления различных математических функций. Все эти классы, константы и функции можно заключить в контекст   math для того, чтобы, разрабатывая программу, использующую наши классы, другой программист не должен был бы выбирать имена, обязательно отличные от тех, что мы использовали.

namespace math
{
     double const pi = 3.1415;
     double sqrt(double x);
     class Complex
     {
     public:
          . . .
     };
};

Теперь к константе pi следует обращаться math::pi.

Контекст может содержать как объявления, так и определения переменных, функций и классов. Если функция или метод определяется вне контекста, ее имя должно быть полностью квалифицировано

double math::sqrt(double x)
{
     . . .
}

Контексты могут быть вложенными, соответственно, имя должно быть квалифицировано несколько раз:

namespace first
{
     int i;
     namespace second    // первый контекст


  // второй контекст  
     {
          int i;
          int whati() { return first::i; }
     // возвращается значение первого i
          int anotherwhat() { return i; }
     // возвращается значение второго i
     }
}
first::second::whati();   // вызов функции

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

double x = pi;
  // ошибка, надо использовать math::pi
using namespace math;
double y = pi;    
  // использовать контекст math
  // теперь правильно
< Лекция 14 || Лекция 15: 12 || Лекция 16 >
Елена Шумова
Елена Шумова

Здравствуйте! Я у Вас прошла курс Язык программировая Си++.

Заказала сертификат. Хочу изменить способ оплаты. Как это сделать?

Маргарита Башкатова
Маргарита Башкатова
Александр Мухаметов
Александр Мухаметов
Казахстан
Айдос Елшибек
Айдос Елшибек