функция-член скрывает свободную функцию - PullRequest
10 голосов
/ 28 января 2012
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        
    }
};

Почему C ++ не может вызвать свободную функцию (единственную с правильной подписью)?

Ответы [ 6 ]

12 голосов
/ 28 января 2012

Поскольку два идентификатора определены в разных областях, и разрешение перегрузки касается только функций в одной и той же области.Как только компилятор обнаруживает, что класс имеет foo, он перестает подниматься до более широких областей (C ++ 11 §3.4.1 / 1), поэтому свободная функция foo скрыта.

Youнеобходимо использовать квалифицированное имя для ссылки на глобальное foo:

::foo(42);
5 голосов
/ 28 января 2012

Логическая причина: Согласованность .

  • Предположим, согласно предложению, компилятор разрешает 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 голосов
/ 28 января 2012

Имя во внутренней области видимости скрывает имена во внешних областях.Неважно, является ли это функцией или чем-то еще, или вы находитесь в классе или пространстве имен.

Только если поиск имени находит несколько функций с одинаковым именем, разрешение перегрузки срабатываетпопробуйте выбрать тот, который лучше всего подходит для вызова.

1 голос
/ 28 января 2012

Очень нравится твой вопрос. Также я могу сказать, используйте этот синтаксис:

::foo(42);

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

namespace MyNameSpace
{
   void foo(int){}

   class X
   {
        void foo(){}

        void bar()
        {
            MyNameSpace::foo(42);
        }
   };
};

Это хорошо, потому что Namespaces позволяет группировать классы, объекты и функции по имени.

PS: Тогда это поможет вам понять смысл записи ::foo(42);, когда у вас нет пространства имен.

0 голосов
/ 28 января 2012

Причиной этого является тот факт, что компилятор сначала будет искать соответствующее имя функции, игнорируя возвращаемые значения и параметры. Находясь внутри класса, он будет пытаться найти соответствующий член там (фактически, он будет просматривать все области, идущие «вверх»: локальную область (и), область действия функции, область класса, область пространства имен, глобальную область и т. Д.). ).

X::foo - первое подходящее имя. ТОГДА (не раньше) он попытается выбрать правильную перегрузку (если существует несколько объявлений) на основе параметров (по этой причине вы можете перегружать одну и ту же функцию разными параметрами, но не только разными возвращаемыми значениями), а затем он проверит возвращаемое значение (если есть).

0 голосов
/ 28 января 2012

Я не могу ответить на вопрос «почему» в вашем вопросе - я не знаю, каково было обоснование этого в спецификации языка.

Чтобы вызвать глобальную функцию в вашем примере, используйте :: синтаксис:

::foo(42);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...