Доступ к глобальной переменной и переменной пространства имен

Я пытаюсь получить доступ к переменной x, используя директиву using в следующем коде:

#include <iostream>
using namespace std;
int x = 10;
namespace e {
int x = 5;
}
int main() {
using namespace e; // Because of this line compiler shows error
cout << x;
return 0;
}

Обычно мы используем следующую строку для доступа к x, но я получаю сообщение об ошибке. Мы также можем использовать using e::x; Но мой вопрос: почему мы не можем использовать using namespace e;< /сильный>


person BethBorgov    schedule 14.01.2021    source источник
comment
Обратите внимание, ошибка не в указанной вами строке, а ниже. Если у вас есть using namespace e;, как компилятор может различать ::x и ::e::x?   -  person Yksisarvinen    schedule 14.01.2021
comment
Не могли бы вы объяснить ясно, поскольку я изучаю эту тему в первый раз?   -  person BethBorgov    schedule 14.01.2021
comment
Отвечает ли это на ваш вопрос? Почему и как использовать пространства имен в C++?   -  person Federico Baù    schedule 14.01.2021
comment
я так не думаю   -  person BethBorgov    schedule 14.01.2021


Ответы (2)


Начнем с другого примера.

const int x = 10;

namespace e {
const int y = 5;
}

int main()
{
std::cout << e::y;
using namespace e;
std::cout << y;
}

Существует переменная со значением 10 и именем x в глобальном пространстве имен (которое можно просто назвать x) и переменная со значением 5 с именем y в пространстве имен e (которое должно называться e::y).

Добавляя using namespace e;, вы вставляете все имена из пространства имен e в глобальное пространство имен. Это означает, что глобальное пространство имен теперь содержит имена x и y, а пространство имен e содержит имя y. Теперь вы можете ссылаться на переменную со значением 5, используя как y, так и e::y.

Теперь вернемся к вашему примеру. Если мы изменим y на x:

const int x = 10;

namespace e {
const int x = 5;
}

int main()
{
std::cout << e::x;
using namespace e;
std::cout << x;
}

В глобальном пространстве имен есть x, а в пространстве имен ex. Добавляя using namespace e;, вы вводите все имена из пространства имен e в глобальное пространство имен, так что теперь глобальное пространство имен содержит имена x и x, а пространство имен e содержит имя x. Видите проблему? Глобальное пространство имен содержит два имени x, что сбивает с толку компилятор. Когда вы пытаетесь вывести переменную под именем x, компилятор ищет имена в глобальном пространстве имен и находит два x. Он не может выбрать, какой из них вы имели в виду, поэтому выдает ошибку.

Это основная причина, по которой using namespace (особенно using namespace std;) считается злом. Можно легко сломать работающий код, обновив библиотеку или внедрив новую функцию. Ошибка компилятора - лучший выход в таком случае, но иногда возможно, что компилятор молча заменит одну функцию на другую, потому что она лучше соответствует.

Вы по-прежнему можете получить доступ к обеим переменным, используя полные имена:

int main()
{
using namespace e;
std::cout << ::x << " "; //x from global with fully quafilied name
std::cout << ::e::x << " "; //x from namespace e with fully qualified name
std::cout << e::x; //not fully qualified, but not ambiguous either - only one x in namespace e
}
person Yksisarvinen    schedule 14.01.2021

В этом примере может показаться, что using namespace e; делает имена из пространства имен e доступными в main области действия функции. Однако он этого не делает. Вместо этого он пытается внедрить имена (во время неквалифицированного поиска в main) из namespace e в ближайшее окружающее пространство имен main и namespace e, то есть в глобальное пространство имен. Поэтому x становится неоднозначным.

person user7860670    schedule 14.01.2021
comment
Не могли бы вы объяснить простыми словами? - person BethBorgov; 14.01.2021
comment
@BethBorgov using namespace e; заставляет компилятор искать имя x в main, как если бы x из пространства имен e было объявлено рядом с int x = 10; в глобальном пространстве имен. - person user7860670; 14.01.2021