6

我对下面的代码有两个问题:

namespace A { class window; }

void f(A::window);

namespace A
{
    class window
    {
    private:
       int a;
       friend void ::f(window);
    };
}

void f(A::window rhs)
{
    std::cout << rhs.a << std::endl;
}

1)为什么我需要通过执行 ::f(window) 将窗口类中的成员函数 f 限定为全局?

2)为什么在这种特殊情况下我需要预先声明函数 f(A::window) ,而当类没有在命名空间内定义时,可以在函数被声明为友元之后声明函数。

4

3 回答 3

4

当您声明f()为朋友时,A如果前向声明尚不存在,则实际上是在包含类的封闭命名空间中完成的(在这种情况下)。

所以这...

namespace A
{
    class window
    {
    private:
        friend void ::f(window);
    };
}

基本上变成了这个……

namespace A
{
    class window;
    void f(window);

    class window
    {
    private:
        friend void f(window);
    };
}

编辑:这是 C++ 标准的一个片段,它明确讨论了这种情况:

标准 7.3.1.2 / 3:

在命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类或函数,则友元类或函数是最内层封闭命名空间的成员。在该命名空间范围内(在授予友谊的类定义之前或之后)提供匹配声明之前,未限定查找 (3.4.1) 或限定查找 (3.4.3) 无法找到朋友的名称。

于 2012-06-07T17:57:02.783 回答
3

至于1),你的函数不在命名空间中,所以你必须使用 :: 告诉编译器在命名空间之外搜索它。

否则,它只会在命名空间内寻找函数(这就是它们存在的原因)。Koenig 查找不适用于此处,因为窗口类位于命名空间内。

虽然不太确定2),但我敢打赌它与1)有关。

于 2012-06-07T17:57:47.783 回答
1

1) 因为函数f是在当前命名空间之外声明和定义的。如果您将类的定义移动到与函数相同的命名空间中,无论是全局还是其他,您都不需要这样做。

2)你总是需要在引用之前声明一个函数。您的类使用friend 语句引用该函数。

于 2012-06-07T17:58:22.327 回答