朋友的功能和方法同名

问题描述 投票:0回答:2

以下类定义声明了一个友元函数,为其提供内联定义。我试图从具有相同名称的友元函数的类方法调用friend函数,但为了使其工作,我必须从封闭的命名空间访问它(这也需要一个前向声明,下面的类C)。为什么名称查找适用于类A,它在类B中不起作用?请注意,B::swap的参数与其友元函数的参数不同。

#include <utility>

struct A {
    A(int x) : v{ x } {}
    friend void swap(A& x, A& y) { std::swap(x.v, y.v); }
    void swapm(A& other) { swap(*this, other); }
private:
    int v;
};

struct B {
    B(int x) : v{ x } {}
    friend void swap(B& x, B& y) { std::swap(x.v, y.v); }
    void swap(B& other) { swap(*this, other); } // <-- This doesn't compile
private:
    int v;
};

struct C;
void swap(C& x, C& y);
struct C {
    C(int x) : v{ x } {}
    friend void swap(C& x, C& y) { std::swap(x.v, y.v); }
    void swap(C& other) { ::swap(*this, other); }
private:
    int v;
};

int main()
{
    A a1{ 1 }, a2{ 2 }; swap(a1, a2); a1.swapm(a2);
    B b1{ 3 }, b2{ 4 }; swap(b1, b2); b1.swap(b2);
    C c1{ 5 }, c2{ 6 }; swap(c1, c2); c1.swap(c2);
}
c++ friend
2个回答
4
投票

无论这是否是一个好主意,这里都解释了为什么它失败了:

编译器使用几个不同的处理阶段来确定您的程序所说的内容。类B不编译的原因是因为在friend被注意到之前发生的失败。让我解释:

当编译器到达试图找出swap意味着什么的点时,它会进行名称查找。它使用特定的规则来指定它应该看起来的位置。这是简化的,但基本上它首先查找在本地作用域中定义的符号,然后在类作用域中查找,然后在封闭(名称空间等)作用域中查找。它找到在类范围中定义的那个,并停止查找。 swap没有采用这两个参数,所以编译失败了。

friend声明允许自由函数访问B的内部,它作为你在全局命名空间中声明的swap函数的附加声明。如果编译器在名称查找中考虑了全局命名空间中的函数,则会考虑这些声明。在类B中,编译器在进入此阶段之前已经停止了处理。 (并且friend声明在更晚的阶段是必要的,当编译器正在编译与swap对象一起使用的B函数的一个版本时,并且想要弄清楚,“在这个函数中称为swap可以采取这些2参数;我可以访问B的内部吗?“)

在课堂上A,你使用的是另一个名字。在找到您的免费​​swap函数之前,名称查找阶段不会成功。在类C中,您已经给出了特定于名称查找的指令,“嘿,当您查找swap时,查看全局命名空间范围,并忽略您可能找到的本地和类范围中的那些。”

(注意:@ PeteBecker评论后更新名称查找和friend的说明。)


0
投票

inline friend?为什么不在这种情况下static?而不是friend?然后创建一个调用static的全局变量。对我来说,这是一个糟糕的设计,而不是一个实际的问题。

方法swap应该是做工作的人而不是friend(因为不再需要朋友):

struct C {
    C(int x) : v{ x } {}
    void swap(C& other) { std::swap(this->v, other.v); }
private:
    int v;
};

void swap(C& x, C& y)
{
  x.swap(y);    
}
© www.soinside.com 2019 - 2024. All rights reserved.