c++ - 同名友元函数和方法

标签 c++ friend

以下类定义声明了一个友元函数,为其提供内联定义。我试图从一个与友元函数同名的类方法中调用友元函数,但为了让它工作,我必须从封闭的命名空间访问它(这也需要一个前向声明,class 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);
}

最佳答案

不管这是个好主意,下面是对失败原因的解释:

编译器使用几个不同的处理阶段来弄清楚你的程序说了什么。类的原因B不编译是因为发生的故障发生在 friend 之前会被注意到。让我解释一下:

当编译器到达它试图弄清楚 swap 是什么的地步时意思是,它进行名称查找。它使用特定的规则来指定应该查看的位置。这是简化的,但基本上它首先查找在局部范围内定义的符号,然后在类范围内,然后在封闭(命名空间等)范围内。它找到在类范围内定义的那个,然后停止查找。那swap不采用这 2 个参数,因此编译失败。

friend声明,它允许自由函数访问 B的内部结构,充当 swap 的附加声明您在全局命名空间中声明的函数。如果编译器在名称查找中考虑全局命名空间中的函数,编译器将考虑这些声明。在类里面B ,编译器在到达这个阶段之前就已经停止处理了。 (并且 friend 声明在更晚的阶段是必要的,当编译器正在编译与 swap 对象一起使用的 B 函数的一个版本时,并且想要弄清楚,“在这个称为swap 可以接受这两个参数;我可以访问 B 的内部结构吗?”)

在类里面A ,您正在使用不同的名称。在找到您的免费​​ swap 之前,名称查找阶段不会成功。功能。在类里面C ,您已经给出了名称查找的具体说明,“嘿,当您查找 swap 时,请查看全局命名空间范围,并忽略您可能会在本地和类范围内找到的那些。”

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

关于c++ - 同名友元函数和方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55101600/

相关文章:

c++ - 类内声明的友元运算符中左手参数的隐式转换

c++ - 什么时候在 OOP 中使用友元是谨慎的?

C++ 友元运算符重载

c++ - 如何在泛型类中用友元函数重载运算符?

c++ - 为什么我不能通过模板参数声明一种类型的友元函数但可以使用别名

c++ - `typedef T this_type` 不需要 T

c++ - 在 C++ 中使用 ifstream 逐行读取文件

c++ - 为什么有时将 2D 图像建模为指向指针 (T**) 的指针?

c++ - 是否定义了静态初始化实现的顺序?

c++ - c++删除一系列节点