Java里有没有友元函数这回事

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java里有没有友元函数这回事相关的知识,希望对你有一定的参考价值。

没有。Java的友元,替代就是package。这个package有两个作用,一个是包内共享,一个是防止命名冲突,实现了C++中friend和namespace的作用。 参考技术A 没有,Java 封装得更实在,尽量避免不必要的编程错误。想达到的目的可以用其它方式做到。本回答被提问者和网友采纳 参考技术B 友元函数只存在C++中,java里没有friend,只能用public,protected,private,package来限制。

关于友元函数定义和命名空间范围

【中文标题】关于友元函数定义和命名空间范围【英文标题】:Regarding friend function definition and namespace scopes 【发布时间】:2017-09-06 11:15:04 【问题描述】:

我正在阅读此blog post section,并尝试使用提供的 sn-p。

namespace N 
// 2
class A 
friend void f(A)  // 1
;

如果我理解正确,// 1 中的定义将在// 2 所在的位置注入名称f。 但是,它只能通过依赖于参数的查找获得。很好。

帖子里有一句话引起了我的注意:

7.3.1.2/3 命名空间成员定义 [namespace.memdef]p3

在命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类、函数、类模板或函数模板,则友元是最内层封闭命名空间的成员。友元声明本身不会使名称对非限定查找 (3.4.1) 或限定查找 (3.4.3) 可见。

请注意,没有任何地方声明由朋友声明引入的名称必须与声明和/或定义它的类的名称有任何特定关系,或者与该类有任何特定关系(就此而言)。

据此,我认为以下 sn-p 是有效的:

namespace N 
struct A 
;

struct B 
  friend void f(A) 

;

int main() 
  N::A a;
  f(a);

但它被 GCC7 和 Clang 4 拒绝。

t.cpp:19:3: 错误:'f' 未在此范围内声明

有趣的是,当我尝试使用 N::B 对象调用 f 时,出现以下错误:

t.cpp:12:6: 错误:无法将“b”从“N::B”转换为“N::A”

这是我的问题:

不应该通过 ADL 检测到 f(A) 吗?由于这两个类都在命名空间中,我不明白为什么会失败。我在标准中查看了关于朋友的部分,但没有找到相关部分。

我想知道f(A) 是在哪个范围内注入的,因为当我尝试通过调用f(B) 给出错误的参数类型时,GCC 能够找到它。

【问题讨论】:

【参考方案1】:

来自cppreference/cpp/language/friend

在类或类模板X 内的友元声明中首次声明的名称成为X 的最内层封闭命名空间的成员,但不可用于查找(考虑X 的参数相关查找除外)除非在命名空间范围内提供了匹配的声明 - 有关详细信息,请参阅 namespaces。


来自cppreference/cpp/language/namespace

由非本地类X 中的友元声明引入的名称成为X 最内层封闭命名空间的成员,但除非在命名空间范围,在类定义之前或之后。这样的名称可以通过 ADL 找到,它同时考虑命名空间和类。


这与您的示例一致 - f 采用 A,这与封闭类的类型不同。

如果您将示例更改为...

namespace N 
struct A 
;

struct B 
  friend void f(B) 

;

int main() 
  N::B b;
  f(b);

...它会编译。


相关标准报价:

$14.3 [class.friend]

类的朋友是一个函数或类,它被授予使用该类的私有和受保护成员名称的权限。 [...]当且仅当该类是非本地类([class.local]),函数名称是非限定的并且该函数具有命名空间范围时,才能在类的朋友声明中定义函数。 [...] 这样的函数隐含地是一个内联函数。 在类中定义的友元函数在定义它的类的(词法)范围内。在类外定义的友元函数不是([basic.lookup.unqual])。

【讨论】:

这是有道理的,但我还有一件事不清楚。 struct Ainnermost enclosing namespace 不是命名空间N 吗?还是编译器会生成隐藏的命名空间?这可以解释为什么 ADL 在我的示例中不起作用。或者可能是因为 ADL 规则中的特殊情况? @Dante:“但不能用于查找(除了考虑 X 的参数相关查找)” - 在这种情况下,XA。您正在尝试通过 B 使用 ADL。 非常感谢,这让我想到了[basic.lookup.argdep]§4.2 和下面的一句话:Any namespace-scope friend functions or friend function templates declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup (11.3) 如果我理解正确的话,这个名字是在编译器之后注入到封闭的命名空间中的检查参数类型类中是否存在友元声明。这是有道理的。

以上是关于Java里有没有友元函数这回事的主要内容,如果未能解决你的问题,请参考以下文章

用于极坐标到矩形转换的坐标类的友元函数

SQL友元函数

C++ friend关键字

什么是友元?

C++入门友元函数详解(定义实现优缺点)

关于声明定义前向声明include循环依赖普通友元函数友元类友元成员函数的总结