1

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

class BaseClass
{
    friend SubClass1;
    friend SubClass2;
}

class SubClass1 : public BaseClass
{
    ...
}

class SubClass2 : public BaseClass
{
    ...
}

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

4

5 回答 5

8

不看库的真实设计很难说,但这两种方法并不等价。与声明所有成员相比,以这种方式使用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
   }
};

在 using 的情况下protected,存在的问题是protected不允许您调整除derived或派生自的类型以外的任何对象的内容derived,但参数可以是 abase或任何其他扩展的类型,base并且与derived.

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

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

对于较小的类型

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

于 2012-04-24T18:05:58.617 回答
7

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

于 2012-04-24T17:29:59.760 回答
4

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

于 2012-04-24T17:31:36.390 回答
1

在示例代码中,将子类设为 a 是没有用的friend。正如您所提到的,最好使其protected子类需要访问的成员。否则就是代码异味

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

于 2012-04-24T17:32:56.793 回答
0

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

于 2012-04-24T17:30:12.847 回答