Что происходит, когда класс и функция имеют одно и то же имя?

#include <iostream>
using namespace std;

struct test
{
    test(){cout<<"class"<<endl;}
};
void test(){cout<<"function"<<endl;}

int main()
{
    test();
    return 0;
}

Вывод:

function  

(VS2013 и gcc 4.8.1)

Почему выбрана функция? Разве это не двусмысленность?


person user3514538    schedule 13.10.2014    source источник
comment
я думаю, что компилятор выбирает функцию, потому что класс никогда не вызывается с его базовым именем. разные контексты...   -  person Leonardo Bernardini    schedule 13.10.2014
comment
Проверьте этот вопрос, он похож: stackoverflow.com/questions/7763802/ @LeonardoBernardini Вы не получите неопределенную функцию, если удалите void test(), потому что тогда компилятор создаст новый тестовый объект, но никуда его не назначит.   -  person Cantfindname    schedule 13.10.2014
comment
вы можете добраться до своего класса с синтаксисом struct test t{};   -  person Piotr Skotnicki    schedule 13.10.2014


Ответы (3)


Это называется скрытием имени и описано в

3.3 Область применения [basic.scope]

3.3.1 Декларативные области и области [basic.scope.declarative]

4) Учитывая набор объявлений в одной декларативной области, каждое из которых указывает одно и то же неполное имя,
— все они должны ссылаться на один и тот же объект или все ссылаться на функции и шаблоны функций; или
— ровно одно объявление должно объявлять имя класса или имя перечисления, которое не является именем typedef, а все остальные объявления должны ссылаться на одну и ту же переменную или перечислитель или все ссылаться на функции и шаблоны функций; в этом случае имя класса или имя перечисления скрыто (3.3.10). [...]

акцент мой.

Обратите внимание, что изменение порядка объявления не влияет на результат:

void test(){cout<<"function"<<endl;}

struct test
{
    test(){cout<<"class"<<endl;}
};

int main()
{
    test();
    return 0;
}

все еще печатает function.

Если это не очевидно, не делайте этого :)

person Luchian Grigore    schedule 13.10.2014
comment
Вы, вероятно, должны указать, что это хак из соображений совместимости с C, и что вы, вероятно, не хотите использовать его в реальном коде. - person James Kanze; 13.10.2014
comment
@JamesKanze Я этого не знал. - person Luchian Grigore; 13.10.2014
comment
Вы не знали, что это было сделано для совместимости с C, или вы не знали, что это плохая идея :-). Настоящая причина этого заключается в поддержке функции Posix stat (у которой есть выходной параметр struct stat*); в C вам нужен struct, а имена после struct ищутся в другом пространстве имен, чем другие. Несколько неуклюжие правила в C++ — это попытка поддержать это, но при этом разрешить использование библиотек C, таких как Posix. (И я уверен, что это было задокументировано в некоторых ранних спецификациях, возможно, ARM.) - person James Kanze; 13.10.2014

Из N3485 §3.3.10 [basic.scope.hiding]/2:

Имя класса (9.1) или имя перечисления (7.2) может быть скрыто именем переменной, элемента данных, функции или перечислителя, объявленных в той же области.

Следовательно, функция имеет приоритет над классом.

Как упоминалось в комментариях, класс по-прежнему доступны через ключевое слово class или struct. Если бы класс имел приоритет, функция была бы недоступна.

person chris    schedule 13.10.2014

Я не уверен, что любой из предыдущих ответов является «почему» для вашего конкретного случая.

Не поймите меня неправильно; Они верны и точны.

Я просто думаю, что это проще.

В вашем примере вы никогда не создаете экземпляр структуры.

Другими словами, вы объявили его, но никогда не использовали.

Поскольку вы никогда не ссылались на него, он никогда не вызывается.

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

Надеюсь это поможет,

-Джон

person John    schedule 13.10.2014
comment
Вы должны цитировать любой источник или документацию, чтобы обосновать свое мнение, или предоставить любые доказательства, подтверждающие его правильность. В этом ответе вы этого не сделали. - person Krzysztof Jabłoński; 13.10.2014
comment
Этот ответ сам по себе даже нелогичен: экземпляр класса никогда не создается, потому что правила приоритета, указанные в других ответах, требуют вызова функции. Если бы правила приоритета были наоборот, был бы создан временный объект и был бы вызван конструктор. Таким образом, говорить о приоритете и тому подобном неприменимо, потому что структура не создается, это просто неправильно. - person Oguk; 14.10.2014