“C ++编程语言”

时间:2017-06-14 11:23:16

标签: c++ inheritance private-inheritance

C ++编程语言,第4版,§20.5.2“访问基类”(第605页)中,它说(关于私有继承):

  

私有基础在通过限制定义类时最有用   基础的接口,以便更强的保证   例如,B是Z.The Vector的实现细节   指针模板,将类型检查添加到其Vector基础   来自§25.3就是一个很好的例子。

尚不清楚Bjarne Stroustrup在这里试图说些什么。如何通过将“接口”限制为基类来定义类? “强有力的保证”是什么意思?

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

even_vector提供比base_vector更强的运行时保证:保证其所有元素均匀。

假设您的base_vector设计为基本类(std::vector通常不会),那么您现在可能会尝试使用公共继承来实现even_vector base_vector。毕竟,功能是相同的,除了even_vector提供的功能之外,您只需在base_vector案例中进行一些额外的运行时检查。但是,如果您在此处使用公共继承,则会违反Liskov Substitution Principle:无论您在何处使用even_vector,都无法使用base_vector。特别是,如果您将奇数插入even_vectorbase_vector将会中断。这很糟糕,因为现在为base_vector编写的所有代码都必须考虑到某些base_vector无法处理奇数的事实。

使用私有继承,您没有此问题:even_vector继承自base_vector的事实是实现的详细信息。客户端无法使用even_vector预期base_vector,因此上述问题不会发生,但我们仍然可以获得代码重用的好处。

话虽如此,使用私有继承进行代码重用是许多人不鼓励的做法。可以说更好的方法是use composition here instead,即将base_vector成员添加到even_vector。这种方法的优点是它严重减少了两个类之间的耦合,因为even_vector不再能够访问base_vector的任何非公共部分。

答案 2 :(得分:0)

  

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

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

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

“强保证”是什么意思?

基数没有给出的任何保证,或者是基数给出的保证的超集。

例如,“行为始终定义良好”的保证强于“仅当输入不为空时才能很好地定义行为”。另一个例子:“函数不抛出”强于“除非复制构造函数抛出”,否则函数不会抛出。。

答案 3 :(得分: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;
}

这给外面的世界提供了“不是毒药”的奶酪 - 也就是说课外的任何东西都不能知道它是毒药,并且它可以被制成'不是毒药'而不会影响使用它的任何东西。

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