私有继承

继承 — privateprotected 继承

如何表达“private 继承”?

当您使用 : private 而不是 : public 时。例如:

class Foo : private Bar {
public:
  // ...
};

private 继承”和“组合”有什么相似之处?

private 继承是组合(又名聚合和/或 has-a)的一种语法变体。

例如,“Car has-a Engine”关系可以使用简单组合来表达。

class Engine {
public:
  Engine(int numCylinders);
  void start();                 // Starts this Engine
};

class Car {
public:
  Car() : e_(8) { }             // Initializes this Car with 8 cylinders
  void start() { e_.start(); }  // Start this Car by starting its Engine
private:
  Engine e_;                    // Car has-a Engine
};

Car has-a Engine”关系也可以使用private 继承来表达。

class Car : private Engine {    // Car has-a Engine
public:
  Car() : Engine(8) { }         // Initializes this Car with 8 cylinders
  using Engine::start;          // Start this Car by starting its Engine
};

这两种变体有几个相似之处:

  • 在这两种情况下,每个 Car 对象中都恰好包含一个 Engine 成员对象。
  • 在这两种情况下,用户(外部人员)都不能将 Car* 转换为 Engine*
  • 在这两种情况下,Car 类都有一个 start() 方法,该方法调用所包含的 Engine 对象的 start() 方法。

也有几个区别:

  • 如果您想在每辆 Car 中包含多个 Engine,则需要简单组合变体。
  • private 继承变体可能会引入不必要的多个继承。
  • private 继承变体允许 Car 的成员将 Car* 转换为 Engine*
  • private 继承变体允许访问基类的 protected 成员。
  • private 继承变体允许 Car 重写 Enginevirtual 函数。
  • private 继承变体使得给 Car 一个 start() 方法,该方法简单地调用 Enginestart() 方法,略微简单一些(20 个字符,而 28 个字符)。

请注意,private 继承通常用于访问基类的 protected 成员,但这通常是一个短期解决方案(翻译:一个权宜之计)。

我应该选择组合还是私有继承?

能用组合时就用组合,必须用 private 继承时才用。

通常,您不希望访问太多其他类的内部,而 private 继承为您提供了这种额外的能力(和责任)。但 private 继承并非邪恶;它只是维护成本更高,因为它增加了某人更改某些内容并破坏您的代码的可能性。

private 继承的一个合法、长期用途是当您想构建一个 class Fred,它使用 class Wilma 中的代码,并且 class Wilma 中的代码需要调用您的新 class Fred 中的成员函数。在这种情况下,Fred 调用 Wilma 中的非 virtual 函数,而 Wilma 调用(通常是纯虚函数)它自己,这些函数由 Fred 重写。这用组合来实现会困难得多。

class Wilma {
protected:
  void fredCallsWilma()
    {
      std::cout << "Wilma::fredCallsWilma()\n";
      wilmaCallsFred();
    }
  virtual void wilmaCallsFred() = 0;   // A pure virtual function
};

class Fred : private Wilma {
public:
  void barney()
    {
      std::cout << "Fred::barney()\n";
      Wilma::fredCallsWilma();
    }
protected:
  virtual void wilmaCallsFred()
    {
      std::cout << "Fred::wilmaCallsFred()\n";
    }
};

我应该将私有派生类指针转换为其基类指针吗?

通常,不应该。

从私有派生类的成员函数或友元内部,与基类的关系是已知的,并且从 PrivatelyDer*Base*(或 PrivatelyDer&Base&)的向上转换是安全的;不需要也不建议进行强制转换。

然而,PrivatelyDer 的用户应避免这种不安全的转换,因为它基于 PrivatelyDer 的私有决定,并且可能在不通知的情况下更改。

protected 继承与 private 继承有什么关系?

相似之处:两者都允许重写 private/protected 基类中的virtual 函数,两者都不声明派生类是其基类的一种。

不同之处:protected 继承允许派生类的派生类了解继承关系。因此,您的“孙子”实际上暴露了您的实现细节。这既有好处(它允许 protected 派生类的派生类利用与 protected 基类的关系)也有成本(protected 派生类不能在不潜在破坏进一步派生类的情况下更改关系)。

Protected 继承使用 : protected 语法。

class Car : protected Engine {
public:
  // ...
};

privateprotected 继承的访问规则是什么?

以这些类为例:

class B                    { /*...*/ };
class D_priv : private   B { /*...*/ };
class D_prot : protected B { /*...*/ };
class D_publ : public    B { /*...*/ };
class UserClass            { B b; /*...*/ };

所有派生类都不能访问 B 中任何 private 的内容。在 D_priv 中,Bpublicprotected 部分是 private。在 D_prot 中,Bpublicprotected 部分是 protected。在 D_publ 中,Bpublic 部分是 publicBprotected 部分是 protectedD_publB 的一种)。class UserClass 只能访问 Bpublic 部分,这“隔离”了 UserClassB

要使 Bpublic 成员在 D_privD_prot 中也为 public,请使用 B:: 前缀声明该成员的名称。例如,要在 D_prot 中使成员 B::f(int,float)public,您可以这样写:

class D_prot : protected B {
public:
  using B::f;  // Note: Not using B::f(int,float)
};