$ 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
成员的可见性。
答案 0 :(得分:94)
通过将继承设为私有,你基本上就是说即使B继承自A(根本不是)也是私有的 - 外部世界无法访问/可见。
如果不允许进行冗长的讨论,如果允许会发生什么,那么简单的事实就是它不被允许。如果你想使用一个指向base的指针来引用派生类型的对象,那么你几乎完全不习惯使用公共继承。
私有继承不必然(或甚至通常)意图遵循Liskov substitution principle。公共继承声明派生对象可以替换基类的对象,并且仍然会产生正确的语义 。私有继承确实不断言。私人继承所暗示的关系的通常描述是“以”来实现。
公共继承意味着派生类维护基类的所有功能,并可能增加更多功能。私有继承通常或多或少地相反:派生类使用通用基类来实现具有更受限制的接口的东西。
例如,让我们假设C ++标准库中的容器是使用继承而不是模板实现的。在当前系统中,std::deque
和std::vector
是容器,std::stack
是容器适配器,提供更受限制的接口。由于它基于模板,因此您可以使用std::stack
作为std::deque
或std::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
的基类。如果D
是B
的无法访问或模糊的基类,则需要进行此转换的程序格式不正确。
答案 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;
}