Когда в C++ две переменные с одинаковым именем могут быть видны в одной области?

StackOverflow https://stackoverflow.com/questions/958625

Вопрос

Этот код иллюстрирует то, что, по моему мнению, следует рассматривать как плохую практику и вызывать предупреждения компилятора о переопределении или маскировке переменной:

#include <iostream>

int *a;

int* f()
{
  int *a = new int;
  return a;
}

int main()
{
  std::cout << a << std::endl << f() << std::endl;
  return 0;
}

Его вывод (скомпилированный с помощью g++):

0
0x602010

Я просмотрел пару ссылок (Stroustrup и The Complete C++ Reference) и не нашел ничего о том, когда и почему это разрешено.Однако я знаю, что это не в пределах одной локальной области.

Когда и почему это разрешено?Есть ли хорошее применение этой конструкции?Как я могу заставить g++ предупредить меня об этом?Другие компиляторы кричат ​​об этом?

Это было полезно?

Решение

Это разрешено, чтобы вы могли безопасно игнорировать переопределение глобального идентификатора.По сути, вас должны интересовать только глобальные имена, которые вы действительно используете.

Предположим, в вашем примере f() были определены в первую очередь.Затем какой-то другой разработчик добавил глобальную декларацию.Добавив имя, f() что раньше работало, работает до сих пор.Если бы переопределение было ошибкой, функция внезапно перестала бы работать, хотя она вообще ничего не делает с вновь добавленной глобальной переменной.

Другие советы

Почему это разрешено:это совершенно справедливо.

Когда вы находитесь внутри функции f(), вы определяете локальную область видимости.Локальные области переопределяют глобальную область, поэтому определение там переменной «a» «скрывает» глобальную область. int *a;

Это совершенно верно, но я думаю, что с -Wall вы получаете предупреждение только тогда, когда затеняете параметр.

Если вам нужны предупреждения, когда вы тень любой тип переменной. Вы можете использовать это из g++ страница руководства:

   -Wshadow
       Warn whenever a local variable shadows another local variable, 
       parameter or global variable or whenever a built-in function is 
       shadowed.

Обратите внимание, что -Wshadow не входит в -Wall по умолчанию.

Многие языки допускают подобные вещи.
Обычно (по отношению ко всем языкам) наиболее локально определяемая переменная — это та, на которую вы ссылаетесь.Из более чем 20 языков, которые я использовал, этот очень распространен.

Кроме того, большинство языков позволяют вам явно ссылаться на тот, который находится во внешней области.
Например, C++ позволяет указать переменную в глобальной области видимости с помощью ::оператор.

#include  <iostream>


int a = 5;
int main()
{
    int a = 6;

    std::cout << a << "\n" << ::a << "\n";
            // Local
                           // global
}

Чтобы ответить, когда это разрешено:в основном в любых двух вложенных областях.

Например:

void foo() {
    int a;
    {
        int a;
    }
}

class Base {
    int a;
};
class Derived: public Base {
    int a; // Yes, the name Base::a is visible in the scope of Derived, even if private
};

class Foo() {
    int a;
    Foo(int a) : a(a) { } // Works OK
};

using std::swap;
void swap(MyClass& lhs, MyClass& rhs);
// Not strictly a variable, but name lookup in C++ happens before determining 
// what the name means.

Теперь ответ должен быть очевидным: наличие двух «вещей» с одним именем в одной области действия обычно разрешено.Это возможно, потому что не более одного из имен на самом деле определенный в этом объеме;другие были бы просто видимый в этом объеме.Правила разрешения имен определяют, какое имя выбирается, если имеется несколько кандидатов.

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

Как уже отмечали другие, это совершенно законно и однозначно для компилятора.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top