$ 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'
$
Run Code Online (Sandbox Code Playgroud)
我只是不明白这个错误.
据我所知,正如本教程所证实的那样,private继承只应改变class B外部世界可见成员的方式.
我认为私有说明者所做的不仅仅是改变class B成员的可见性.
Jer*_*fin 96
通过使继承成为私有,你基本上说,即使B继承自A(根本不是)的事实是私有的 - 外部世界无法访问/可见.
如果没有进行冗长的讨论,如果允许会发生什么,那么简单的事实就是它不被允许.如果你想使用一个指向base的指针来引用派生类型的对象,那么你几乎要坚持使用公共继承.
私有继承并不一定(甚至常)打算遵循Liskov替换原则.公有继承断言派生对象可以取代基类的一个对象,和正确的语义将仍然导致.但是私有继承没有断言.私人继承所暗示的关系的通常描述是"以"来实现".
公共继承意味着派生类维护基类的所有功能,并可能增加更多功能.私有继承通常或多或少地相反:派生类使用通用基类来实现具有更受限制的接口的东西.
例如,让我们假设C++标准库中的容器是使用继承而不是模板实现的.在当前系统中,std::deque并且std::vector是容器,并且std::stack是提供更受限制的接口的容器适配器.由于它基于模板,因此您可以将std::stack其用作任何一个std::deque或的适配器std::vector.
如果我们想要提供与继承基本相同的东西,我们可能会使用私有继承,所以std::stack会是这样的:
class stack : private vector {
// ...
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们绝对不希望用户能够stack像操作一样操纵我们vector.这样做可能(并且可能会)违反堆栈的期望(例如,用户可以在中间插入/移除项目,而不是按照预期的纯粹堆栈方式).我们基本上使用它vector作为一种方便的方式来实现我们的堆栈,但是如果(例如)我们改变了stack独立的实现(不依赖于基类)或者重新实现它std::deque,我们不希望这样影响任何客户端代码 - 对于客户端代码,这应该只是一个堆栈,而不是一些特殊的vector(或deque).
Ben*_*igt 11
私有继承应该只改变B类成员对外界可见的方式
确实如此.而如果
A* p = new B;
Run Code Online (Sandbox Code Playgroud)
被允许,然后任何人的继承成员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.
Run Code Online (Sandbox Code Playgroud)
我不是C++专家,但看起来它只是不被允许.我会围绕规范进行讨论,看看我想出了什么.
编辑:这是规范中的相关参考 - 第4.10节指针转换,第3段:
类型为"指向cv的 指针"的prvalue
D,其中D是类类型,可以转换为类型为"指向cv的指针"的prvalueB,其中B是基类D.如果B是不可访问或模糊的基类D,则需要进行此转换的程序格式不正确.
它非常简单:A私有地继承的事实意味着B扩展的事实A是一个秘密,只是B"知道"它.这就是私有继承的定义.