Функция-член скрывает свободную функцию
void foo(int)
{
}
class X
{
void foo()
{
}
void bar()
{
foo(42);
// error: no matching function for call to 'X::foo(int)'
// note: candidate is:
// note: void X::foo()
// note: candidate expects 0 arguments, 1 provided
}
};
Почему С++ не может вызвать свободную функцию (которая является единственной с правильной сигнатурой)?
Ответы
Ответ 1
Логическая причина Консистенция.
- Предположим, что в соответствии с предложением компилятор разрешает
foo(42)
на
::foo(int)
.
- Теперь, после некоторого времени, если вы измените
X::foo()
на X::foo(int)
, тогда
foo(42)
будет разрешено до X::foo(int)
. Что несовместимо.
Это также причина, по которой производная функция класса скрывает функцию базового класса, когда есть похожие имена.
Такие случаи можно разрешить двумя способами:
(1) Дайте полное имя (например, ::foo(42)
)
(2) Используйте утилиту using
; например.
void bar()
{
using ::foo;
foo(42);
}
Ответ 2
Поскольку два идентификатора определены в разных областях, а разрешение перегрузки касается только функций в той же области. Как только компилятор обнаружит, что класс имеет foo
, он перестает подниматься до более широких областей (С++ 11 §3.4.1/1), поэтому свободная функция foo
скрыта.
Вам нужно использовать квалифицированное имя для ссылки на глобальный foo
:
::foo(42);
Ответ 3
Имя во внутренней области скрывает имена во внешних областях. Не имеет значения, является ли это функцией или чем-то еще, или если вы находитесь в классе или пространстве имен.
Только если поиск имени найдет несколько функций с тем же именем, будет разрешено перегрузочное разрешение, чтобы попытаться выбрать тот, который наилучшим образом соответствует вызову.
Ответ 4
Действительно, как ваш вопрос. Также я могу сказать, используйте этот синтаксис:
::foo(42);
Но я могу сказать, что, на мой взгляд, это более элегантное и хорошее программирование, задайте пространства имен, чтобы вы могли написать что-то вроде этого:
namespace MyNameSpace
{
void foo(int){}
class X
{
void foo(){}
void bar()
{
MyNameSpace::foo(42);
}
};
};
Это хорошо, потому что Namespaces
позволяет группировать классы, объекты и функции под именем.
PS: Затем это поможет вам понять смысл записи ::foo(42);
, если у вас нет пространства имен.
Ответ 5
Я не могу ответить на вопрос о части вашего вопроса - я не знаю, в чем причина этого в спецификации языка.
Чтобы вызвать глобальную функцию в вашем примере, используйте синтаксис:
::foo(42);
Ответ 6
Причиной этого является тот факт, что компилятор сначала ищет подходящее имя функции, игнорируя возвращаемые значения и параметры. Когда внутри класса он попытается найти подходящий элемент там (фактически, он будет просматривать все области, идущие "вверх", локальная область (области), область действия, область класса, область пространства имен, глобальная область действия и т.д.).
X::foo
- первое совпадающее имя. THEN (не раньше) попытается выбрать правильную перегрузку (если есть несколько деклараций) на основе параметров (именно по этой причине вы можете перегружать одну и ту же функцию разными параметрами, но не только с разными значениями возврата), а затем она будет проверять возвращаемое значение (если оно есть).