Область видимости (scope) переменной — часть кода, из которой возможен обычный доступ к переменной по её имени. Отвечает на вопрос «где имя обозначает именно этот объект».

Зачем нужно

Будет ли ошибка?

int x = 0;
 
int main() {
  int x = 1;
  std::cout << x << '\n';
  return 0;
}

Нет, программа выведет 1. Две переменные с одним именем существуют одновременно, и правила видимости решают, какую из них обозначает x в каждой строке.

Как работает

Видимость не больше, чем существование

Область видимости не может быть больше области действия: нельзя увидеть по имени объект, который уже не существует. Но может быть меньше. В примере выше глобальная x продолжает существовать во время выполнения main, но локальная переменная с тем же именем скрывает глобальное имя.

Поиск от внутреннего к внешнему

По умолчанию поиск имени идёт от наиболее вложенной области к менее вложенной:

int x = 0;
 
int main() {
  int x = 1;
 
  {
    int x = 2;
    std::cout << x << '\n';  // 2
  }
 
  return 0;
}

Компилятор сначала ищет x в самом внутреннем блоке, находит int x = 2; и использует её.

Операция ::

Чтобы обратиться именно к глобальной переменной, есть операция разрешения области видимости ::. Она говорит компилятору: искать имя нужно в глобальной области.

int x = 0;
 
int main() {
  int x = 1;
 
  {
    int x = 2;
    std::cout << x << '\n';    // 2
    std::cout << ::x << '\n';  // 0
  }
 
  return 0;
}

Тонкости

  • К промежуточной локальной x = 1 по имени из внутреннего блока обратиться нельзя: внутренняя x её скрывает, а ::x ведёт сразу в глобальную область.
  • Скрытие имени — не ошибка компиляции. Программа соберётся и молча будет работать с другой переменной.
  • Два вопроса не смешивать: область действия — где объект существует; область видимости — где объект доступен по имени. Иногда они почти совпадают (одна локальная переменная в main), иногда объект существует, а имя временно скрыто.

Частые ошибки

  • Завести во вложенном блоке переменную с тем же именем, что снаружи, и ожидать, что изменения попадут во внешнюю.
  • Думать, что ::x означает «переменная на уровень выше». Она означает «глобальная переменная».