繁体   English   中英

基类的好友类如何通过从基类派生的类的对象访问该基类的成员?

[英]How does friend class of the base class access members of that base class through objects of class derived from the base class?

这是我在文件source.cpp中的代码:

class B
{
  friend class F;
protected:
  int protectedIntB;
};

class D : public B {};

class F
{
public:
  int f(D &d) {return ++d.protectedIntB;}
};

当我使用g++ -c -Wall -pedantic -std=c++11 source.cppcl /c source.cpp编译以上代码时,两个编译器均成功编译。 但是,当我使D使用protected而不是public从B继承时:

class D : protected B {};

这次,gcc成功编译,而cl给出错误,表明B::protectedIntBreturn ++d.protectedIntB;不可访问return ++d.protectedIntB;

另一种情况是将public替换为private

class D : private B {};

这次,两个编译器都产生错误。 顺便说一句,我正在使用mingw-w64构建的gcc版本5.3.0和VS2015的cl版本19.00.24210。

我的问题来了:

基类的好友类如何通过从基类派生的类的对象访问该基类的成员,以及为什么gcc和cl处理不同?

编辑:

感谢songyuanyaoBrian ,在protected情况下,它似乎在gcc 5.3.0中存在错误。 只有public情况才能成功编译,并且gcc 6.1.0也可以正常工作。

根据[class.access.base] / 5:

对成员的访问受该成员所在的类影响。 该命名类是在其中查找并找到成员名称的类。

根据[class.access.base] / 6:

如果使用包含隐式“ this-> ”的类成员访问运算符来访问非静态数据成员或非静态成员函数,则如果左操作数(在指针中被视为指针)则引用格式不正确。 “ . ”运算符大小写)不能隐式转换为指向右侧操作数命名类的指针。

因此,在特定情况下,要访问d.protectedIntB ,以下两个条件必须为真:

  • 您必须作为B的成员有权访问protectedIntB ,因为B是在其中找到了protectedIntB名称的类。 (注意:这可以通过使用using-声明在派生类中重新声明成员来更改在这种情况下,派生类将是控制对象。)

  • 您必须有权访问B作为D的基础, 即,能够将D*转换为B* 如果BD的公共基础,则很好。 如果B是一个受保护的基础D ,访问检查适用,这F::f失败,因为F不是朋友D ,而不是派生类的D

令人惊讶的是,在受保护的情况下,似乎GCC是错误的编译器,但此错误似乎已修复 注意Clang提供了更好的诊断

如果使D使用受保护的或私有的(而不是公共的)从B继承,则编译将失败。

根据标准, $ 11.2 / 5基类和基类成员的可访问性[class.access.base]

如果在类N中命名,则成员m在点R处可访问。

(5.4)存在一个N的基类B,它可以在R处访问,而在B类中命名时,m可以在R处访问。

 class B; class A { private: int i; friend void f(B*); }; class B : public A { }; void f(B* p) { p->i = 1; // OK: B* can be implicitly converted to A*, // and f has access to i in A } 

—结束示例]

对于您的第一种情况,可以通过F::f()访问D的基类B ,因为它是公共继承。 B::protectedIntBF::f()类的朋友,因为它是B类的朋友。

如果将其更改为受保护继承或私有继承,则D的基类B不能再次在F::f()访问,则编译应会失败。 注意F::f()不是派生类D朋友。 这意味着如果您也使它成为D类的朋友,则编译将成功。

顺便说一句:我在这里用gcc尝试了受保护的继承,但失败了。

如果代码在gcc 5.3.0上编译而不在cl上编译,则这两者之一没有严格执行C ++标准的可能性很高。 如果我不得不猜测一下,对于受保护的私有继承,您应该会遇到编译器错误。 有关不同种类的继承之间的区别,请参阅私有,公共和受保护继承之间的区别以获取更多详细信息。

为了使F类能够访问B类的私有成员,应该知道D类是从B类派生的,而B类只会发生在公共继承中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM