0

The C++ Programming Language , 4th Edition 的第 20.5.2 节“访问基类”(第 605 页)中,它说(关于私有继承):

当通过将接口限制为基类来定义类时,私有基类最有用,这样可以提供更强的保证。例如,B 是 Z 的实现细节。指针模板的向量从§ 25.3 就是一个很好的例子。

目前尚不清楚 Bjarne Stroustrup 在这里想说什么。如何通过将“接口”限制为基础来定义类?他所说的“更有力的保证”是什么意思?

4

4 回答 4

2

让我们举一个非常简单的例子:

// A simple class with a *public* member
class A
{
public:
    int a;
};

// Use private inheritance
class B : private A
{
public:
    int b;
};

// Use public inheritance
class C : public A
{
public:
    int c;
};

// ...

B my_b;
my_b.a = 0;  // Invalid, the member a is private due to the private inhericance

C my_c;
my_c.a = 0;  // Valid, because the inheritance is public

private继承限制了对基类成员的访问。即使A::a成员变量是public,由于private继承它成为private子类中的B

于 2017-06-14T11:31:29.387 回答
1

让我们继续看向量的例子。向量只是Ts 的容器。现在假设您要构建一个行为类似于向量的类型,但添加了一些额外的运行时检查。我现在手头没有 TC++PL 的副本,所以我们来做一个约束:例如,假设你的向量只允许包含偶数。尝试插入奇数将导致运行时错误。让我们称这个新类even_vector和没有运行时检查的版本base_vector

even_vector提供比 更强的运行时保证base_vector:保证其所有元素都是偶数。

假设您base_vector的设计目的是作为基类很好地工作(std::vector通常不会),您现在可能很想使用公共继承来实现even_vector. base_vector毕竟,功能是一样的,你只需要even_vectorbase_vector. 然而,如果你在这里使用公共继承,你将违反里氏替换原则:你不能在even_vector任何你使用 a 的地方使用 a base_vector。特别是,even_vector在您将奇数插入base_vector. 这很糟糕,因为现在编写的所有代码都base_vector必须考虑以下事实:base_vectors 不能处理奇数。

使用私有继承,您就没有这个问题:这里even_vector继承自的事实base_vector是实现的细节。客户端不能even_vectorbase_vector期望的地方使用,所以上面的问题不会发生,但我们仍然得到代码重用的好处。

话虽如此,使用私有继承来重用代码是许多人不鼓励的做法。一个可以说是更好的方法是在这里使用组合,也就是说,添加一个私有base_vector成员来even_vector代替。这种方法的优点是它大大减少了两个类之间的耦合,因为even_vector不再能够访问base_vector.

于 2017-06-14T11:39:44.743 回答
0

让我们看看一个可能的情况,使用接口来帮助构建图片。

class poison {
  public:
    virtual void used() = 0;
};

class food {
  public:
    virtual void eat();
  protected:
    void poisonConsumed(poison& p);
}

class cheese : public food, private poison {
  public:
    virtual void eat() override {
      poisonConsumed(*this);
    }
  private:
    void used() override;
}

这将奶酪向外界展示为“不是毒药”——即班级以外的任何人都无法知道它是毒药,并且可以将其制成“不是毒药”,对任何使用它的东西都没有影响。

然而,奶酪可以将自己传递给任何期待毒药的东西,然后可以自由调用 used(); 即使它在奶酪中是私有的。

于 2017-06-14T12:32:06.737 回答
0

如何通过将“接口”限制为基础来定义类?

通过将继承设为私有。当继承为私有时,基类的接口仅限于成员函数,外部不可用。访问说明符可以在基础列表中给出:

class A : private B
//        ^^^^^^^

他所说的“更有力的保证”是什么意思?

基础未提供的任何保证,或者是基础提供的保证的超集。

例如,“行为总是明确定义”的保证比“只有当输入不为空时行为才明确定义”要强。另一个例子:“The function does not throw”“The function will not throw unless the copy constructor throws”强。

于 2017-06-14T11:32:23.103 回答