10
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++ 无法调用 free 函数(这是唯一具有正确签名的函数)?

4

6 回答 6

12

因为这两个标识符是在不同的作用域中定义的,而重载解析只关注同一作用域中的函数。一旦编译器发现该类有一个foo,它就会停止爬升到更广泛的范围(C++11 §3.4.1/1),所以 free 函数foo被隐藏了。

您需要使用限定名称来引用全局foo

::foo(42);
于 2012-01-28T12:23:08.833 回答
5

合乎逻辑的原因是Consistency

  • 假设根据建议,编译器解析foo(42)::foo(int).
  • 现在一段时间后,如果您更改X::foo()X::foo(int)then foo(42)将被解析为X::foo(int). 这是不一致的。

这也是派生类函数在名称相似时隐藏基类函数的原因。

这种情况可以通过两种方式解决;

(1) 给出完全限定的名称(例如::foo(42)

(2) 使用using效用;例如

void bar()
{
  using ::foo;
  foo(42);
}
于 2012-01-28T12:25:49.380 回答
2

内部作用域中的名称隐藏外部作用域中的名称。它是函数还是其他东西,或者您是否在类或命名空间中都没有关系。

只有当名称查找找到多个具有相同名称的函数时,重载决议才会开始尝试选择与调用最匹配的函数。

于 2012-01-28T12:52:07.893 回答
1

真的很喜欢你的问题。我也可以说,使用这种语法:

::foo(42);

但我可以说,在我看来,它是更优雅和更好的编程,设置命名空间,所以你可以写这样的东西:

namespace MyNameSpace
{
   void foo(int){}

   class X
   {
        void foo(){}

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

这是一件好事,因为Namespaces允许在一个名称下对类、对象和函数进行分组。

PS:::foo(42);那么这可以帮助您在没有任何命名空间的情况下理解 write 的含义。

于 2012-01-28T12:45:11.493 回答
0

我无法回答您问题的部分原因——我不知道语言规范中的原因是什么。

要在您的示例中调用全局函数,请使用 :: 语法:

::foo(42);
于 2012-01-28T12:25:40.033 回答
0

原因是编译器会首先寻找匹配的函数名,而忽略返回值和参数。当在一个类中时,它会尝试在那里寻找匹配的成员(事实上,它会查看所有“向上”的范围;局部范围、函数范围、类范围、命名空间范围、全局范围等。 )。

X::foo是第一个匹配的名称。然后(不是之前)它会尝试根据参数选择正确的重载(如果有多个声明)(这就是你可以用不同的参数重载同一个函数但不能只用不同的返回值的原因)然后它会检查返回值(如果有的话)。

于 2012-01-28T12:28:39.627 回答