隐藏自由函数的成员函数

member function hiding free function

本文关键字:函数 成员 隐藏 自由      更新时间:2023-10-16
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 函数(这是唯一具有正确签名的函数(?

因为这两个标识符在不同的作用域中定义,并且重载解析只涉及同一作用域中的函数。一旦编译器发现该类有foo,它就会停止爬升到更宽的范围(C++11 §3.4.1/1(,因此自由函数foo被隐藏。

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

::foo(42);

合乎逻辑的原因是一致性

  • 假设按照建议,编译器解析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);
}

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

仅当名称查找找到多个具有相同名称的函数时,重载解决方案才会启动,以尝试选择最适合调用的函数。

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

::foo(42);

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

namespace MyNameSpace
{
   void foo(int){}
   class X
   {
        void foo(){}
        void bar()
        {
            MyNameSpace::foo(42);
        }
   };
};

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

PS:然后这可以帮助您理解没有任何命名空间时写::foo(42);的含义。

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

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

::foo(42);

这样做的原因是,编译器将首先查找匹配的函数名称,忽略返回值和参数。当在一个类中时,它将尝试在那里寻找匹配的成员(事实上,它将查看所有"向上"的作用域;本地作用域,函数作用域,类作用域,命名空间作用域,全局作用域等(。

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