【发布时间】:2019-02-26 13:38:08
【问题描述】:
我有一个关于私有继承的小众问题。我也有这个问题的解决方案,但我不明白它为什么有效。
TL;DR
为什么某些中间级别的私有继承会阻止我将基类型作为参数传递给(私有)派生类?
考虑下面的代码(也可以在这里找到http://cpp.sh/3p5zv5):我有一个复合类型类,它可以包含指向它自己类型的子元素的指针。此外,该类包含模板方法 MyMethodTemplate(T value),允许任何类型的参数。我需要多次从这个类继承,这样 MyMethodTemplate(T) 不可用,而只能使用例如类型化版本 MyMethod() 调用整数,字符串,等等。
由于派生类将包含大量样板代码(此处未显示),我编写了从 cComposite 私有继承的类模板 cSpecializedComposite(成功隐藏了 MyMethodTemplate())。它的方法 MyMethod() 在内部从其父类调用 MyMethodTemplate()。到目前为止,一切顺利。
现在,为了摆脱最终用户代码中的模板参数,我想编写从模板公开继承的普通类(cSpecializedCompositeInt、cSpecializedCompositeString...)。我的假设是 cSpecializedCompositeInt 会知道 cSpecializedComposite 的接口,但不知道它的内部。在 cSpecializedCompositeInt 的构造函数中,我可以选择传递一个 unique_ptr 的向量,该向量将传递给它的父构造函数(天知道用它做什么,这里没什么可看的,继续前进)。请注意,cComposite 的类定义对 cSpecializedCompositeInt 是可见的,即使 cSpecializedCompositeInt 没有从它继承,据它所知。
但是,我在 cSpecializedCompositeInt 的构造函数中收到编译器错误 C2247,告诉我不能使用 cComposite,因为 cSpecializedComposite 是从它私下继承的。这发生在 msvc10 和 GCC 4.9.2(http://cpp.sh 后面的编译器)上。
将私有继承更改为受保护允许 cSpecializedCompositeInt 知道它是从 cComposite 间接继承的,并且编译器错误消失了。
这与Private Inheritance and Derived Object to Base reference 有多大关系?
#include <vector>
#include <memory>
class cComposite
{
public:
cComposite(std::vector<std::unique_ptr<cComposite>>&& vecC)
: m_vecC(std::move(vecC))
{
//empty
}
template <typename T>
void MyTemplateMethod(T value)
{
//do something with any type of value
}
private:
std::vector<std::unique_ptr<cComposite>> m_vecC;
};
template <typename MySpecialType>
class cSpecializedComposite : private cComposite
{
public:
cSpecializedComposite(std::vector<std::unique_ptr<cComposite>>&& vecC)
: cComposite(std::move(vecC))
{
//empty
}
void MyMethod(MySpecialType value)
{
//allow only MySpecialType as Input, call base class template method to do something
cComposite::MyTemplateMethod(value);
}
};
class cSpecializedCompositeInt : public cSpecializedComposite<int>
{
public:
cSpecializedCompositeInt(std::vector<std::unique_ptr<cComposite>>&& vecC)
: cSpecializedComposite(std::move(vecC))
{
//empty
}
};
int main(int argc, char* argv[])
{
std::vector<std::unique_ptr<cComposite>> vecC;
cSpecializedCompositeInt spec(std::move(vecC));
spec.MyMethod(5);
return 0;
}
【问题讨论】:
-
因为私有继承意味着私有。继承的一切都是私有的。甚至是私有继承类的基类,无论它们是否是公共的。
-
我想的也差不多。我的问题是,为什么基类实际上对派生类不可见,而不是仅仅阻止它们知道它们从谁继承,也就是使内部接口对它们不可用?
-
因为
private使类可以随时更改其私有继承的对象,并且破坏任何 API 的风险为 0%。由于除了类之外没有其他人知道它的私有继承来源,因此可以随时更改类的私有继承。它甚至可以完全删除。因此,只有类本身需要更改。与其从基类公开继承,不如考虑使用虚拟公共继承。现在,可以从任何子类访问虚拟公共类。 -
谢谢,这个理由对我来说很有意义。但是,我仍然可以在我的最终用户代码中构造和使用 cSpecializedComposite
,在其构造函数中传递 cComposite,尽管模板类是从 cComposite 私有继承的。使派生类完全无法访问私有基类似乎有点奇怪,但其他人(即最终用户)没有。我敢肯定它背后有一个基本原理,我可以让它休息,但它仍然看起来很奇怪。
标签: c++ inheritance