繁体   English   中英

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

[英]Inheritance: 'A' is an inaccessible base of 'B'

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

我只是不明白这个错误。

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

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

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

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

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

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

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

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

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

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

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

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

确实如此。 而如果

A* p = new B;

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

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指针”类型的纯右值(其中D是类类型)可以转换为“指向 cv B指针”类型的纯右值,其中 B 是D的基类。 如果BD的不可访问或不明确的基类,则需要这种转换的程序是格式错误的。

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

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

这是工作

#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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM