C++ 继承:“A”是“B”的不可访问的基础

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9661936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:08:33  来源:igfitidea点击:

Inheritance: 'A' is an inaccessible base of 'B'

c++inheritance

提问by Lazer

$ 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.

我只是不明白这个错误。

As I understand, and as this tutorialconfirms, privateinheritance should only change how the members of class Bare visible to the outside world.

据我了解,正如本教程所确认的那样,private继承应该只改变 的成员对class B外界可见的方式。

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

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

  • What do I get this error and what does it mean?
  • Basically what is wrong with allowing this type of code in C++? Looks totally harmless.
  • 我得到这个错误是什么意思?
  • 基本上在 C++ 中允许这种类型的代码有什么问题?看起来完全无害。

回答by Jerry Coffin

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.

通过将继承设为私有,您基本上是在说,即使 B 从 A 继承(根本)这一事实也是私有的——外部世界无法访问/可见。

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.

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

Private inheritance is notnecessarily (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 willstill result. Private inheritance does notassert that though. The usual description of the relationship implied by private inheritance is "is implemented in terms of".

私有继承并不一定(甚至常)打算遵循Liskov替换原则。公有继承断言派生对象可以取代基类的一个对象,和正确的语义仍然导致。私有继承并没有断言这一点。私有继承所隐含的关系的通常描述是“是根据……实现的”。

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.

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

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::dequeand std::vectorare containers, and std::stackis a container adapter that provides a more restricted interface. Since it is based on templates, you can use std::stackas an adapter for either std::dequeor std::vector.

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

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

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

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

In this case, we definitely do notwant the user to be able to manipulate our stackas 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 vectoras a convenient way to implement our stack, but if (for example) we changed the implementation for stackstand alone (with no dependence on a base class) or re-implement it in terms of std::deque, we do notwant 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).

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

回答by Ben Voigt

private inheritance should only change how the members of class B are visible to the outside world

私有继承应该只改变 B 类成员对外界可见的方式

It does. And if

确实如此。而如果

A* p = new B;

were allowed, then the inherited members of any Bcould be accessed from the outside world, just by making a A*. Since they're privately inherited, that access is illegal, and so is the upcast.

被允许,则B可以从外部世界访问any 的继承成员,只需创建一个A*. 由于它们是私下继承的,因此访问是非法的,上行也是如此。

回答by Carl Norum

clang++gives a slightly more understandable error message:

clang++给出了一个更容易理解的错误信息:

example.cpp:9:13: error: cannot cast 'B' to its private base class 'A'
    A* ab = new B;
            ^
example.cpp:6:11: note: declared private here
class B : private A { };
          ^~~~~~~~~
1 error generated.

I'm not a C++ expert, but it looks like it's just simply not allowed. I'll go poke around the spec and see what I come up with.

我不是 C++ 专家,但看起来这只是不允许的。我会去看看规范,看看我想出了什么。

Edit: here's the relevant reference from the spec - Section 4.10 Pointer conversions, paragraph 3:

编辑:这是规范中的相关参考 - 第4.10指针转换,第 3 段:

A prvalue of type "pointer to cvD", where Dis a class type, can be converted to a prvalue of type "pointer to cv B", where B is a base class of D. If Bis an inaccessible or ambiguous base class of D, a program that necessitates this conversion is ill-formed.

类型为“指向cv 的指针”的纯右值D,其中D是类类型,可以转换为类型为“指向 cv 的指针”的纯右值B,其中 B 是 的基类D。如果B是 的不可访问或模棱两可的基类D,则需要进行此转换的程序是格式错误的。

回答by Ernest Friedman-Hill

It's pretty simple: the fact that Ais inherited privately means that the fact that Bextends Ais a secret, and only B"knows" it. That is the very definition of private inheritance.

这很简单:A私下继承的事实意味着B扩展的事实A是一个秘密,只有B“知道”它。这就是私有继承的定义。

回答by tmpearce

Private inheritance means that outside the derived class, the inheritance information is hidden. That means you can't cast the derived class to the base class: the relationship isn't known to the caller.

私有继承意味着在派生类之外,继承信息是隐藏的。这意味着您不能将派生类强制转换为基类:调用者不知道这种关系。

回答by Deniz Babat

This is working

这是工作

#include <iostream>

using namespace std;

class A{
    public:
        virtual void update() = 0;
};

class B: public A{
    public:
    virtual void update(){std::cout<<"hello";};
};

int main()
{
    A *a = new B();

    a->update();

    return 0;
}