在 C ++编程语言,第4版,§20.5.2“访问基类”(第605页)中,它说(关于私有继承):
私有基础在通过限制定义类时最有用 基础的接口,以便更强的保证 例如,B是Z.The Vector的实现细节 指针模板,将类型检查添加到其Vector基础 来自§25.3就是一个很好的例子。
尚不清楚Bjarne Stroustrup在这里试图说些什么。如何通过将“接口”限制为基类来定义类? “强有力的保证”是什么意思?
答案 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_vector
,base_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;
}
这给外面的世界提供了“不是毒药”的奶酪 - 也就是说课外的任何东西都不能知道它是毒药,并且它可以被制成'不是毒药'而不会影响使用它的任何东西。
然而,奶酪可以将自己传递给任何期望毒药的东西,然后可以自由地使用();即使它在奶酪中是私密的。