为什么要将子类定义为其自己的父类的好友

Why define a subclass as a friend of its own parent class?

本文关键字:自己的 父类 好友 子类 定义 为什么      更新时间:2023-10-16

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

class BaseClass
{
    friend SubClass1;
    friend SubClass2;
}
class SubClass1 : public BaseClass
{
    ...
}
class SubClass2 : public BaseClass
{
    ...
}

以这种方式设计类层次结构有什么好处吗?如果你想从子类访问 BaseClass 的私有方法,你会不会将它们移动到受保护而不是私有?我觉得这里有一个成语我错过了。

如果不看库的真实设计,很难说,但这两种方法并不等同。以这种方式使用 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
   }
};

在使用的情况下 protected ,问题是protected不允许你调整除derived或派生自derived的类型以外的任何对象的内容,但参数可以是base或任何其他扩展base的类型,并且与derived无关。

在其他一些用例中,此限制不太清楚,您可能能够访问您自己的层次结构之外的那些受保护成员,只是不是以直接简单的方式(我认为这是语言的访问说明符规范中的错误)。

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

到较小的类型

protected访问说明符是可传递的,一旦通过protected授予对派生类型的访问权限,就会将其授予派生自该类型的所有类型的,以及可能直接从您继承的任何其他类型。无法控制哪些类型被授予访问权限,哪些类型不被授予访问权限。另一方面,友谊是精确的,只有声明为朋友类型的成员才能访问。友谊不是可传递的,因此除了您声明的好友之外,还可以访问其他类型。

我不知道有任何特定的习语涉及这一点,但一个简单的答案可能是他们希望只向许多子类中的几个子类公开私有成员。或者,他们可能根本不了解受保护成员的概念。

不确定成语,但一种可能性是你还有其他子类。 这样,朋友就可以访问,但不能访问其他子类。

在示例代码中,没有用friend 的子类。正如你提到的,最好让成员protected其子类需要访问的内容。否则就是代码异味

但是,有一种真实的情况是,必须将子类作为其基类的friend。这是你想要创建一个final class的时候(就像在Java中一样)。下面是解释该极端情况的示例代码。

我认为这只是一个糟糕的编程。真的想不出任何你可以从这样的定义中受益的情况。