简体   繁体   English

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

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

Here is my codes in file source.cpp: 这是我在文件source.cpp中的代码:

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

class D : public B {};

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

When I compile above codes with g++ -c -Wall -pedantic -std=c++11 source.cpp and cl /c source.cpp , both compilers compile successfully. 当我使用g++ -c -Wall -pedantic -std=c++11 source.cppcl /c source.cpp编译以上代码时,两个编译器均成功编译。 However, when I make D inherits from B using protected instead of public : 但是,当我使D使用protected而不是public从B继承时:

class D : protected B {};

This time, gcc compiles successfully while cl gives an error says that B::protectedIntB is inaccessible in return ++d.protectedIntB; 这次,gcc成功编译,而cl给出错误,表明B::protectedIntBreturn ++d.protectedIntB;不可访问return ++d.protectedIntB; .

Another situation is replacing public with private : 另一种情况是将public替换为private

class D : private B {};

This time, both compilers yield errors. 这次,两个编译器都产生错误。 By the way I'm using gcc version 5.3.0 built by mingw-w64 and cl version 19.00.24210 from VS2015. 顺便说一句,我正在使用mingw-w64构建的gcc版本5.3.0和VS2015的cl版本19.00.24210。

Here comes my question: 我的问题来了:

How does friend class of the base class access members of that base class through objects of class derived from the base class, and why gcc and cl handle it differently? 基类的好友类如何通过从基类派生的类的对象访问该基类的成员,以及为什么gcc和cl处理不同?

Edit: 编辑:

Thanks to songyuanyao and Brian , it seems a bug in gcc 5.3.0 in the protected case. 感谢songyuanyaoBrian ,在protected情况下,它似乎在gcc 5.3.0中存在错误。 Only the public case should be compiled successfully, and gcc 6.1.0 also works fine. 只有public情况才能成功编译,并且gcc 6.1.0也可以正常工作。

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

The access to a member is affected by the class in which the member is named. 对成员的访问受该成员所在的类影响。 This naming class is the class in which the member name was looked up and found. 该命名类是在其中查找并找到成员名称的类。

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

If a class member access operator, including an implicit “ this-> ,” is used to access a non-static data member or non-static member function, the reference is ill-formed if the left operand (considered as a pointer in the “ . ” operator case) cannot be implicitly converted to a pointer to the naming class of the right operand. 如果使用包含隐式“ this-> ”的类成员访问运算符来访问非静态数据成员或非静态成员函数,则如果左操作数(在指针中被视为指针)则引用格式不正确。 “ . ”运算符大小写)不能隐式转换为指向右侧操作数命名类的指针。

Therefore, in your particular case, in order to access d.protectedIntB , both of the following must be true: 因此,在特定情况下,要访问d.protectedIntB ,以下两个条件必须为真:

  • You have to have access to protectedIntB as a member of B , since B is the class in which the name protectedIntB was found. 您必须作为B的成员有权访问protectedIntB ,因为B是在其中找到了protectedIntB名称的类。 (Note: this can be altered by redeclaring the member in the derived class using a using-declaration; in that case the derived class would be controlling.) (注意:这可以通过使用using-声明在派生类中重新声明成员来更改在这种情况下,派生类将是控制对象。)

  • You have to have access to B as a base of D , ie, be able to convert D* to B* . 您必须有权访问B作为D的基础, 即,能够将D*转换为B* If B is a public base of D , fine. 如果BD的公共基础,则很好。 If B is a protected base of D , an access check applies, which F::f fails since F is not a friend of D and is not a derived class of D . 如果B是一个受保护的基础D ,访问检查适用,这F::f失败,因为F不是朋友D ,而不是派生类的D

Surprisingly, it seems that GCC is the compiler that's wrong in the protected case but this bug appears fixed . 令人惊讶的是,在受保护的情况下,似乎GCC是错误的编译器,但此错误似乎已修复 Note that Clang gives a much better diagnostic . 注意Clang提供了更好的诊断

If you make D inherits from B using protected or private instead of public, compilation should fail. 如果使D使用受保护的或私有的(而不是公共的)从B继承,则编译将失败。

From the standard, $11.2/5 Accessibility of base classes and base class members [class.access.base] : 根据标准, $ 11.2 / 5基类和基类成员的可访问性[class.access.base]

A member m is accessible at the point R when named in class N if 如果在类N中命名,则成员m在点R处可访问。

(5.4) there exists a base class B of N that is accessible at R, and m is accessible at R when named in class B. [ Example: (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 } 

— end example ] —结束示例]

For your 1st case, the base class B of D is accessible at F::f() , because it's public inheritance. 对于您的第一种情况,可以通过F::f()访问D的基类B ,因为它是公共继承。 And B::protectedIntB is accessible at F::f() because it's friend of class B . B::protectedIntBF::f()类的朋友,因为它是B类的朋友。

If you change it to protected or private inheritance, the base class B of D is not accessible at F::f() again, then compilation should fail. 如果将其更改为受保护继承或私有继承,则D的基类B不能再次在F::f()访问,则编译应会失败。 Note F::f() is not friend of derived class D . 注意F::f()不是派生类D朋友。 It means if you make it friend of class D too, compilation will succeed. 这意味着如果您也使它成为D类的朋友,则编译将成功。

BTW: I tried the protected inheritance with gcc here and it failed. 顺便说一句:我在这里用gcc尝试了受保护的继承,但失败了。

If the code compiles on gcc 5.3.0 and does not compile on cl, probability is high that one of the two does not strictly enforce C++ standard. 如果代码在gcc 5.3.0上编译而不在cl上编译,则这两者之一没有严格执行C ++标准的可能性很高。 If I have to take a guess, for protected and private inheritance, you should get a compiler error. 如果我不得不猜测一下,对于受保护的私有继承,您应该会遇到编译器错误。 For the difference between different kind of inheritances see Difference between private, public, and protected inheritance for more details. 有关不同种类的继承之间的区别,请参阅私有,公共和受保护继承之间的区别以获取更多详细信息。

For the class F to be able to access the private members of class B, It should know that class D derives from class B which will only happen for public inheritance. 为了使F类能够访问B类的私有成员,应该知道D类是从B类派生的,而B类只会发生在公共继承中。

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

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