22

我正在阅读 Scott Meyers 的Effective C++(第三版),在第32 条的一段中:确保公共继承是第 151 页的“is-a”,他发表了评论(我用粗体表示):

这仅适用于公共继承。只有当 Student 是公开派生自 Person 时,C++ 才会像我所描述的那样运行。私有继承意味着完全不同的东西(参见第 39 条),而受保护的继承是我至今仍无法理解的东西。

问题:我应该如何解释这个评论?Meyers 是否试图传达受保护的继承很少被认为有用并且应该避免?

(我已经阅读了 私有、公共和受保护继承之间的区别以及C++ FAQ Lite 的私有和受保护继承部分的问题,两者都解释了受保护继承的含义,但并没有让我深入了解何时或为什么它会很有用。)

4

5 回答 5

10

您希望受到保护的一些场景:

  1. 您有一个带有方法的基类,您知道您永远不想在外部公开功能,但您知道这对任何派生类都有用。

  2. 您有一个基类,其成员应该由任何扩展该类的类在逻辑上使用,但绝不应该暴露在外面。

由于多重继承,您可以使用基类的继承类型,并使用现有的逻辑和实现构造一个更加多样化的类。

一个更具体的例子:

您可以创建一些遵循设计模式逻辑的抽象类,假设您有:

Observer
Subject
Factory

现在你希望这些都是公开的,因为一般来说,你可以在任何东西上使用这个模式。

但是,使用受保护的继承,您可以创建一个观察者和主题的类,但只有受保护的工厂,因此工厂部分仅用于继承的类。(只是为示例选择了随机模式)

另一个例子:

例如,假设您想从库类继承(我不鼓励这样做)。假设你想让你自己的酷扩展std::list<>或“更好” shared_ptr

您可以从基类(设计为具有公共方法)受保护地派生。
这将使您可以选择使用自己的自定义方法,使用类的逻辑,并将逻辑传递给任何派生类。

您可能可以改用封装,但继承遵循IS A的正确逻辑 (或者在这种情况下是一种 A)

于 2011-06-26T13:49:56.567 回答
5

他并不是完全不鼓励受保护的继承,他只是说他没有找到任何好的用途。我在其他地方也没有见过任何人。

如果你碰巧发现了几个真正有用的用例,你可能也有写书的材料。:-)

于 2011-06-26T13:58:02.337 回答
3

是和不是。我自己认为受保护的继承也是一个不好的特性。它基本上将所有基类的公共和受保护成员作为受保护成员导入。

我通常避免使用受保护的成员,但在最低级别上,使用链接时优化不佳的编译器需要极高的效率,它们是有用的。但是基于此构建的所有内容都不应该与原始基类的(数据)成员混淆,而是使用接口。

我认为 Scott Meyer 想说的是,如果它解决了问题,您仍然可以使用受保护的继承,但请确保使用注释来描述继承,因为它在语义上并不清晰。

于 2011-06-26T13:53:54.177 回答
3

是的,受保护或私有继承的用途并不多。如果您曾经考虑过私有继承,那么组合可能更适合您。(继承意味着'is-a',组合意味着'has-a'。)

我的猜测是 C++ 委员会只是简单地添加了这个,因为它很容易做到,他们认为,“哎呀,也许有人会发现这个很好用”。这不是一个坏功能,它不会造成任何伤害,只是还没有人发现它有任何真正的用途。:P

于 2011-06-26T14:08:00.580 回答
2

我不知道 Meyers 是否建议我们不要使用受保护的继承,但如果 Meyers 在您的团队中,您似乎应该避免使用它,因为至少他无法理解您的代码。

除非您的同事比他更了解 C++,否则您可能还应该远离受保护的继承。每个人都会理解替代方案,即使用组合。

然而,我可以想象一个可能有意义的情况:您需要访问一个类中的受保护成员,其代码您无法更改,但您不想公开 IS-A 关系。

class A {
protected:
  void f(); // <- I want to use this from B!
};

class B : protected A {
private:
  void g() { f(); }
};

即使在这种情况下,我仍然会考虑使用公共继承制作一个包装器,该包装器使用公共方法公开受保护的基成员,然后使用这些包装器进行组合。

/*! Careful: exposes A::f, which wasn't meant to be public by its authors */
class AWithF: public A {
public:
  void f() { A::f(); }
};

class B {
private:
  AWithF m_a;
  void g() { m_a.f(); }
};
于 2011-06-27T15:57:15.580 回答