为什么将子类定义为其父类的朋友?

wha*_*ter 1 c++

很久以前,我正在查看由一位(现已离职)的同事编写的一些C++代码,并发现了一个奇怪的类定义,我正试图破译.

class BaseClass
{
    friend SubClass1;
    friend SubClass2;
}

class SubClass1 : public BaseClass
{
    ...
}

class SubClass2 : public BaseClass
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

以这种方式设计类层次结构有好处吗?如果你想从子类访问BaseClass的私有方法,你不会只是将它们移动到protected而不是private吗?我觉得这里有一个成语我不见了.

Dat*_*ore 7

我不知道涉及这个问题的任何特定习语,但一个简单的答案可能是他们希望将私人成员只暴露给许多子类中的几个子类.或者,他们可能很容易理解受保护成员的概念.


Dav*_*eas 6

没有看图书馆的真实设计很难说,但这两种方法并不相同.通过friend这种方式使用,可以通过声明所有成员来提供对比较少类型的访问权限protected.

更好的访问

其含义protected并不完全是对所有派生类型的所有基本成员的访问权限,而是授予对派生类型内基础子对象的受保护成员的访问权限.不同之处在于派生类型无法访问受保护的成员或不属于其自身类型或派生类型的类型.

考虑一个类的两个版本,其中所有成员都受到保护而没有友元声明,另一个版本的所有成员都是私有的,并将子类声明为朋友.现在考虑派生类型有一个函数:

struct derived : base {
   void f( base& b ) {
       //std::cout << b.protected_method() << std::endl; // Error
       std::cout << protected_method() << std::endl;     // Ok, accessing your own base
   }
};
Run Code Online (Sandbox Code Playgroud)

在使用的情况下,protected存在的问题是protected不允许您调整除了derived派生的类型之外的任何对象的内容derived,但是参数可以是base扩展的任何其他类型,base也不是与其相关的任何其他类型derived.

在其他一些使用案例中,这种限制有点不太明确,您可能能够获得对您自己的层次结构之外的受保护成员的访问权限,而不是以直接简单的方式(我认为访问说明符规范中的错误)语言).

另一方面,如果derivedbase上述代码的朋友将编译,因为derived被授予访问base任何地方的每个实例,无论是否是子对象derived.

对于较小的类型

protected访问说明符是transtive,一旦您完成授予访问权限protected到派生类型,你是它授予从它派生的所有类型,同时也可能直接从你继承任何其他类型.无法控制哪些类型被授予访问权限,哪些类型不被授予访问权限.另一方面,友谊是准确的,只有声明为朋友的类型的成员才能访问.友谊不是传递性的,因此除了您声明的朋友之外的类型将具有访问权限.