В С++, каково разрешение области (порядок приоритета) для затененных имен переменных?

Каково в C++ разрешение области ("порядок приоритета") для теневых имен переменных? Я не могу найти краткий ответ в Интернете.

Например:

#include <iostream>

int shadowed = 1;

struct Foo
{
    Foo() : shadowed(2) {}

    void bar(int shadowed = 3)
    {
        std::cout << shadowed << std::endl;
            // What does this output?

        {
            int shadowed = 4;
            std::cout << shadowed << std::endl;
                // What does this output?
        }
    }

    int shadowed;
};


int main()
{
    Foo().bar();
}

Я не могу думать ни о каких других областях, где переменная может конфликтовать. Пожалуйста, дайте мне знать, если я пропустил один.

Каков порядок приоритета для всех четырех переменных shadow внутри функции-члена bar?


person Emile Cormier    schedule 10.05.2010    source источник
comment
У вас может быть блок кода внутри bar(), который также объявляет shadowed.   -  person Carl Norum    schedule 10.05.2010
comment
Добавлен регистр для блока кода внутри bar().   -  person Emile Cormier    schedule 10.05.2010
comment
@Ignacio: Вы имели в виду, что разрешение области действия является подходящим термином для обозначения порядка приоритета в отношении затенения?   -  person Emile Cormier    schedule 10.05.2010


Ответы (2)


Ваш первый пример выводит 3. Ваш второй выводит 4.

Общее эмпирическое правило заключается в том, что поиск идет от «наиболее локальной» к «наименее локальной» переменной. Следовательно, приоритет здесь следующий: блок -> локальный -> класс -> глобальный.

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

// See http://ideone.com/p8Ud5n
#include <iostream>

int shadowed = 1;

struct Foo
{
    int shadowed;
    Foo() : shadowed(2) {}
    void bar(int shadowed = 3);
};

void Foo::bar(int shadowed)
{
    std::cout << ::shadowed << std::endl; //Prints 1
    std::cout << this->shadowed << std::endl; //Prints 2
    std::cout << shadowed << std::endl; //Prints 3
    {
        int shadowed = 4;
        std::cout << ::shadowed << std::endl; //Prints 1
        std::cout << this->shadowed << std::endl; //Prints 2
        //It is not possible to print the argument version of shadowed
        //here.
        std::cout << shadowed << std::endl; //Prints 4
    }
}

int main()
{
    Foo().bar();
}
person Billy ONeal    schedule 10.05.2010

Он должен распечатать 3. Основное правило состоит в том, чтобы в основном работать в обратном направлении по файлу к самому последнему определению, которое увидел бы компилятор (редактировать: это не вышло за рамки), и это то, что он использует. Для переменных, которые являются локальными для класса, вы следуете тому же за исключением того, что все переменные класса обрабатываются так, как если бы они были определены в начале определения класса. Обратите внимание, что это более или менее уникально для классов. Например, данный код вида:

int i;

int x() { 
    std::cout << i << '\n'; // prints 0;
    int i=1;
}

Несмотря на то, что имеется i, локальное для функции, самое последнее определение, где используется cout, является глобальным, поэтому именно на него ссылается i в этом выражении. Если бы, однако, это было в классе:

int i;

class X { 
    void y() { std::cout << i << "\n"; }

    X() : i(2) {}

    int i;
};

Тогда выражение cout будет ссылаться на X::i, даже несмотря на то, что его определение еще не было видно при анализе y.

person Jerry Coffin    schedule 10.05.2010
comment
«переменные, локальные для класса» Лучше сказать: переменные, которые являются членами класса. - person Melebius; 14.03.2017