С++ позволяет переопределить глобальную (константную) переменную?

Меня немного смущают глобальные константы. Насколько я понимаю (начальный уровень), «глобальные» переменные определяются вне блока и имеют область действия программы (источник: http://www.learncpp.com/cpp-tutorial/42-global-variables/). Но программа:

#include <iostream>

const double x=1.5;

int main(){
        std::cout << "1) x=" << x << std::endl;
        double x=2.5;
        std::cout << "2) x=" << x << std::endl;
        //const double x=3.5;
        return 0;
}

компилируется в g++ (GCC, последняя 64-битная версия) без проблем, даже с -Wall.

Выход:

1) x=1.5
2) x=2.5

Это сбивает меня с толку. Тот факт, что первая оценка cout означает, что main распознает «x» как «глобальную» переменную (она не была определена в области видимости main). Если это так, то почему он позволяет мне переопределить «x»?

Затем, если вы раскомментируете третье объявление с комментариями, g++ выдаст ошибку повторного объявления. Это означает, что мое первое объявление не могло быть «глобальным» в том смысле, который я определил: S

редактировать: хорошо, вопрос не имеет ничего общего с глобальными переменными, но с областями действия: например, та же проблема в http://pastebin.com/raw.php?i=V5xni19M


person badger5000    schedule 11.10.2013    source источник
comment
Вы затеняете глобальную переменную локальной. double x объявляет новый локальный double, скрывая глобальный. Вы не переопределяете его.   -  person Simple    schedule 11.10.2013
comment
Дальнейшее чтение: stackoverflow.com/questions/4269034/   -  person Moo-Juice    schedule 11.10.2013


Ответы (6)


#include <iostream>

const double x=1.5;

На данный момент в коде есть один объект с именем x в глобальной области, и он имеет тип const double.

int main(){
        std::cout << "1) x=" << x << std::endl;

На данный момент видим только один x (глобальный), так что это то, на что указывает имя x.

        double x=2.5;

На этом этапе кода вы ввели объект с именем x в область действия main(). Эта область вложена в глобальную область, поэтому теперь у вас есть два объекта с именами x:

  1. x в глобальной области видимости типа const double

  2. x в составе main() типа double

Локальный x скрывает глобальный x. Если вы хотите получить доступ к глобальному x внутри main(), вы можете обратиться к нему как ::x.

    std::cout << "2) x=" << x << std::endl;
    double x=3.5;  //uncommented

Нет, вы пытаетесь ввести другой объект с именем x в область действия main(). Это невозможно, в этой области уже есть один x, поэтому он не работает.

person Angew is no longer proud of SO    schedule 11.10.2013
comment
Спасибо! Хорошо, оказывается, что вопрос не имеет ничего общего с глобальными переменными, а скорее с моим непониманием повторного объявления во вложенных областях. например, вопрос также может быть задан как pastebin.com/raw.php?i=V5xni19M. Для этого кода мне кажется концептуально странным, что компилятор позволяет мне во второй области определить переменную с тем же типом и именем, что и уже существующая (я еще не вышел из первой области). Это только я? Похоже, это может вызвать проблемы в более крупных проектах, и это то, от чего я сейчас точно устану. - person badger5000; 11.10.2013
comment
@JohnnyLyco Хотя иногда это может привести к путанице, это фундаментальное свойство областей видимости в C++. В каком-то смысле это еще одна причина избегать глобальных переменных вообще. - person Angew is no longer proud of SO; 11.10.2013

Второй x не является переопределением. Это hiding глобальный x. Это то, на что стоит обратить внимание, особенно при работе с наследованием:

  struct Base 
  {
      void AwesomeFunction() { }
  };

  struct Derived : public Base
  {
      // This definition 'hides' Base::AwesomeFunction
      void AwesomeFunction() { }
  };

Это скрытие разрешено только потому, что второй x находится в меньшей области, чем глобальный x. Вы получаете ошибку redfinition для третьего x, потому что третий и второй x находятся на одном и том же уровне области видимости.

person thelamb    schedule 11.10.2013

Используйте ::x для доступа к глобальной переменной из вашей программы. Прямо сейчас вы создаете локальную переменную и глобальную. Когда вы впервые печатаете x, он не может найти локальный, поэтому предполагает, что вы имели в виду глобальный. После того, как вы сделаете свой локальный x, он больше не будет по умолчанию глобальным.

person Steven    schedule 11.10.2013

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

person Or Cyngiser    schedule 11.10.2013

Объявления во внутренней области (например, main) могут затенять объявления во внешней области (например, в области файла). Ваше третье объявление x находится в той же области, что и второе, так что это ошибка повторного объявления.

person john    schedule 11.10.2013

Вы не переопределяете глобальную переменную; вы определяете отдельную локальную переменную с тем же именем.

C++ позволяет вам повторно использовать имя для объявления чего-то еще в более узкой области, подобной этой; технически объявление во внутренней области скрывает объявление во внешней области, так что между объявлением и концом функции x ссылается на локальную переменную. Вы по-прежнему можете получить доступ к глобальной переменной, указав ее пространство имен: ::x.

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

person Mike Seymour    schedule 11.10.2013