【问题标题】:Member access control for friend function defined inside class in C++C++ 类中定义的友元函数的成员访问控制
【发布时间】:2020-04-15 10:02:29
【问题描述】:

我知道下面的 C++ 代码 sn-p 应该会在 g 的定义中产生错误,因为 p.t.x 是私有的,不能在那里访问。

class P {
  class T {
    int x;
    friend class P;
  };
  T t;

  friend void g(P &p);
};

void g(P &p) { p.t.x = 42; }

让我困惑的是下一个sn-p。不同之处仅在于友元函数g定义 现在出现在内部P

class P {
  class T {
    int x;
    friend class P;
  };
  T t;

  friend void g(P &p) { p.t.x = 42; }
};

Clang++(6.0.0-1ubuntu2 和 Apple 版本 clang-1100.0.33.8)编译后者没有错误,而 GNU C++(7.5.0-3ubuntu1~18.04)产生与前者相同的错误 sn-p .

我了解后一种情况下定义的函数g不在同一个范围内 正如前者中定义的那样(参见related questionolder longer discussion),它只能通过 ADL 看到。但我认为我在这里问的是不同的:T 类中的声明 friend class P 是否应该扩展到朋友函数 g 的主体?

C++ 标准的相关部分(最近的drafts 中的 §11.3 或 §11.9.3)指出:

7 ... 类中定义的友元函数在(词法)范围内 定义它的类。外部定义的友元函数 该类不是(6.5.1)。

所以我知道 Clang++ 和 GNU C++ 对“词法范围”的含义有不同的解释(另请参阅 this answer 到上一个相关问题)。 Clang++ 似乎编译 g 就好像它是类 T 的朋友,可能是因为它在类 P 的词法范围内,这是类 T 的朋友,而 GNU C++ 没有。

  1. 两个编译器之一是否存在错误?
  2. 如果是,是哪一个?
  3. 不管前面问题的答案如何,这不是标准应该更好地形式化的东西吗?

【问题讨论】:

  • @Scheff 指出的other question 相似,因为它显示了 Clang++ 和 GNU C++ 解释标准的方式不同,(恕我直言)可能更清楚。然而,歧义的对象在这里有所不同。

标签: c++ g++ language-lawyer clang++ friend-function


【解决方案1】:

这看起来像CWG1699(仍然打开)。

1699。与班级交朋友会与班级朋友交朋友吗?

根据 14.3 [class.friend] 第 2 段,

将一个类声明为友元意味着授予友元的类的私有成员和受保护成员的名称可以在友元类的基说明符和成员声明中访问。

friend 声明是一个成员声明,但尚不清楚在朋友声明中授予友谊的程度。例如:

  class c {
    class n {};
    friend struct s;
  };

  struct s {
    // #1 and #2 are not relevant for this question
    friend void f() { c::n(); } // #3
  }; 

特别是,如果在类定义中定义了一个友元函数,如 #3 中那样,它的定义是否可以访问友元类的私有成员和受保护成员?在这一点上,实现有所不同。

【讨论】:

  • 你说得对,这与我的问题有很大关系,我真的很惊讶这样的问题仍然存在。另一方面,1699 提出了一个更基本的问题。如果确实与一个班级交朋友就是与它的朋友交朋友,我不明白为什么我的问题中的第一个 sn-p 应该是错误的。
【解决方案2】:

对于初学者 - 免责声明:这是我对标准的解释,尽管我认为它是正确的,但无法确定其真正含义。

tl;博士

  1. 是的。
  2. IMO 铿锵++
  3. 如果您看下面,您会发现它的形式化得非常好。

完整答案

话虽如此,我认为标准中有两个相关的引用。首先是这样的:

11.9 会员访问控制

1 一个类的成员可以是

(1.1) - 私有的;也就是说,它的名称只能由声明它的类的成员和朋友使用。

第二个是:

11.9.3 朋友 [class.friend]

1 类的朋友是一个函数或类,它被授予使用该类的私有和受保护成员名称的权限。 一个类通过友元声明指定它的友元(如果有的话)。 此类声明赋予朋友特殊的访问权限,但它们不会使指定的朋友成为交友类的成员

从这两个可以推断出一些事情。但最重要的一点是,即使是内联好友也无法访问定义在被友好类中的类的私有成员。为什么?因为它既不是嵌套类的成员也不是朋友。由此看来,g++ 就在这里。

【讨论】:

  • 问题是 [class.friend] 中的第二段说名称可以在 member declarations 被友好的类中访问。并且朋友声明是一个成员声明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多