继承:'A'是'B'无法访问的基础

时间:2012-03-12 04:55:21

标签: c++ inheritance

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

我只是不明白这个错误。

据我了解,并且this tutorial确认,private继承应该只会改变class B成员对外界可见的方式。

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

  • 我该怎么得到这个错误?这是什么意思?
  • 基本上在C ++中允许这种类型的代码有什么问题?看起来完全无害。

6 个答案:

答案 0 :(得分:94)

通过将继承设为私有,你基本上就是说即使B继承自A(根本不是)也是私有的 - 外部世界无法访问/可见。

如果不允许进行冗长的讨论,如果允许会发生什么,那么简单的事实就是它不被允许。如果你想使用一个指向base的指针来引用派生类型的对象,那么你几乎完全不习惯使用公共继承。

私有继承必然(或甚至通常)意图遵循Liskov substitution principle。公共继承声明派生对象可以替换基类的对象,并且仍然会产生正确的语义 。私有继承确实断言。私人继承所暗示的关系的通常描述是“以”来实现。

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

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

如果我们想提供与继承基本相同的东西,我们可能会使用私有继承,因此std::stack将是这样的:

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

在这种情况下,我们肯定希望用户能够操纵我们的stack,就好像它是vector一样。这样做可能(并且可能会)违反堆栈的期望(例如,用户可以在中间插入/移除项目,而不是如预期的那样纯粹的堆栈方式)。我们基本上使用vector作为实现堆栈的便捷方式,但是如果(例如)我们改变了stack的实现(不依赖于基类)或重新实现就std::deque而言,我们希望它影响任何客户端代码 - 对于客户端代码,这应该只是一个堆栈,而不是一些专门的矢量(或者deque)。

答案 1 :(得分:11)

  

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

确实如此。如果

A* p = new B;

被允许,然后可以通过制作B从外部世界访问任何A*的继承成员。由于它们是私人继承的,因此该访问是非法的,而且也是非法的。

答案 2 :(得分:7)

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.

我不是C ++专家,但看起来它只是不被允许。我会绕过规范,看看我想出了什么。

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

  

类型为“指向 cv D的指针”的prvalue,其中D是类类型,可以转换为“指向cv {{的指针”的prvalue 1}}“,其中B是B的基类。如果DB的无法访问或模糊的基类,则需要进行此转换的程序格式不正确。

答案 3 :(得分:5)

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

答案 4 :(得分:3)

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

答案 5 :(得分:0)

这正在工作

#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;
}
相关问题