继承:“A"是“B"的不可访问的基础

2021-12-17 00:00:00 inheritance c++
$ cat inheritance.cpp 
#include <iostream>

using namespace std;

class A { };
class B : private A { };

int main() {
    A* ab = new B;
}
$
$ g++ inheritance.cpp
inheritance.cpp: In function 'int main()':
inheritance.cpp:9: error: 'A' is an inaccessible base of 'B'
$

我只是不明白这个错误.

I just do not understand this error.

据我所知,以及本教程 确认,private 继承应该只改变 class B 的成员对外界可见的方式.

As I understand, and as this tutorial confirms, private inheritance should only change how the members of class B are visible to the outside world.

我认为私有说明符不仅仅是在这里改变 class B 成员的可见性.

I think the private specifier is doing more than just change visibility of class B members here.

  • 为什么在继承时会出现此错误?这是什么意思?
  • 在 C++ 中允许这种类型的代码基本上有什么问题?看起来完全无害.

推荐答案

通过将继承设为私有,您基本上是在说,即使 B 从 A 继承(完全)也是私有的――不可访问/可见外面的世界.

By making the inheritance private, you're basically saying that even the fact that B inherits from A (at all) is private -- not accessible/visible to the outside world.

没有对如果允许会发生什么进行冗长的讨论,简单的事实是它是不允许的.如果您想使用指向基类的指针来引用派生类型的对象,那么您几乎只能使用公共继承.

Without getting into a long-winded discussion of what would happen if it was allowed, the simple fact is that it's not allowed. If you want to use a pointer to base to refer to an object of derived type, then you're pretty much stuck with using public inheritance.

私有继承不一定(或什至通常)遵循Liskov替代原则.公共继承断言派生对象可以替换基类的对象,并且仍然会产生正确的语义将.私有继承不会不断言这一点.私有继承所隐含的关系的通常描述是以...实现".

Private inheritance is not necessarily (or even normally) intended to follow the Liskov substitution principle. Public inheritance asserts that a derived object can be substituted for an object of the base class, and proper semantics will still result. Private inheritance does not assert that though. The usual description of the relationship implied by private inheritance is "is implemented in terms of".

公共继承意味着派生类维护基类的所有功能,并可能添加更多功能.私有继承通常意味着或多或少相反:派生类使用通用基类来实现具有更受限接口的东西.

Public inheritance means a derived class maintains all the capabilities of the base class and potentially adds more besides. Private inheritance often means more or less the opposite: that the derived class uses a general base class to implement something with a more restricted interface.

仅举个例子,让我们暂时假设 C++ 标准库中的容器是使用继承而不是模板实现的.在当前系统中,std::dequestd::vector 是容器,std::stack 是容器适配器,提供了一个更受限制的接口.由于它基于模板,您可以使用 std::stack 作为 std::dequestd::vector 的适配器.

Just for example, let's assume for the moment that the containers in the C++ standard library were implemented using inheritance rather than templates. In the current system, std::deque and std::vector are containers, and std::stack is a container adapter that provides a more restricted interface. Since it is based on templates, you can use std::stack as an adapter for either std::deque or std::vector.

如果我们想提供本质上相同的继承,我们可能会使用私有继承,所以 std::stack 应该是这样的:

If we wanted to provide essentially the same with inheritance, we would probably use private inheritance, so std::stack would be something like:

class stack : private vector {
    // ...
};

在这种情况下,我们绝对不希望用户能够操作我们的stack,就好像它是一个vector.这样做可能(并且可能会)违反堆栈的期望(例如,用户可以在中间插入/删除项目,而不是像预期的那样纯粹的类似堆栈的方式).我们基本上使用 vector 作为实现堆栈的便捷方式,但是如果(例如)我们单独更改了 stack 的实现(不依赖于基础class) 或根据 std::deque 重新实现它,我们不希望它影响任何客户端代码――对于客户端代码,这应该是只是一个堆栈,而不是某种特殊的向量(或双端队列).

In this case, we definitely do not want the user to be able to manipulate our stack as if it were a vector. Doing so could (and likely would) violate the expectations of a stack (e.g., the user could insert/remove items in the middle, rather than a purely stack-like fashion as intended). We're basically using vector as a convenient way to implement our stack, but if (for example) we changed the implementation for stack stand alone (with no dependence on a base class) or re-implement it in terms of std::deque, we do not want that to affect any client code -- to the client code, this is supposed to be just a stack, not some specialized variety of vector (or deque).

相关文章