C++ 将私有父类类型作为参数传递(C2247)

C++ 将私有父类类型作为参数传递(C2247),c++,inheritance,C++,Inheritance,关于私人继承,我有一个相当小的问题。我也有解决这个问题的办法,但我不明白为什么它能奏效 TL;博士 为什么某些中间级别的私有继承阻止我将基类型作为参数传递给私有派生类 考虑下面的代码:我有一个复合类型类,它可以包含指向它自己类型的子元素的指针。另外,该类包含模板方法MyMethodTemplateT值,允许任何类型的参数。我需要多次从这个类继承,这样MyMethodTemplateT就不可用,而只能使用int、string等类型调用类型化版本的MyMethod 由于派生类将包含许多此处未显示的样

关于私人继承,我有一个相当小的问题。我也有解决这个问题的办法,但我不明白为什么它能奏效

TL;博士

为什么某些中间级别的私有继承阻止我将基类型作为参数传递给私有派生类

考虑下面的代码:我有一个复合类型类,它可以包含指向它自己类型的子元素的指针。另外,该类包含模板方法MyMethodTemplateT值,允许任何类型的参数。我需要多次从这个类继承,这样MyMethodTemplateT就不可用,而只能使用int、string等类型调用类型化版本的MyMethod

由于派生类将包含许多此处未显示的样板代码,因此我编写了类模板CSSpecializedComposite,该模板从cComposite中私自继承,成功隐藏了MyMethodTemplate。其方法MyMethod从其父类内部调用MyMethodTemplate。到目前为止,一切顺利

现在,为了去掉最终用户代码中的模板参数,我想编写一些简单的类,这些类公开继承自模板CsSpecializedCompositeInt、CsSpecializedCompositeString等。。。。我的假设是CSSpecializedCompositeInt将知道CSSpecializedComposite的接口,但不知道其内部。在CSSpecializedCompositeInt的构造函数中,我可以选择性地传递一个唯一的向量,该向量被传递给其父构造函数,父构造函数用它做什么,天知道,这里什么都看不到,继续前进。请注意,即使CSSpecializedCompositeInt不从其继承(据其所知),cComposite的类定义对CSSpecializedCompositeInt也是可见的

但是,我在CsSpecializedCompositeInt的构造函数中得到一个编译器错误C2247,告诉我不能使用CcoComposite,因为CsSpecializedComposite是从它私下继承的。这在msvc10和GCC 4.9.2编译器上都发生过

将私有继承更改为受保护允许CSSpecializedCompositeInt知道它是从cComposite间接继承的,并且编译器错误消失

这与我们的关系有多远


此网站上经常出现的主题之一是请求访问。您在完整和可验证的部分上做得很好,但在最小的部分上做得不太好。请允许我简化您的代码,以删除可能分散注意力的细节

// Base class, constructed from a type that involves itself.
class A {
public:
    A(A *) {}
};

// Intermediate class, derives privately from the base class.
class B : private A {
public:
    B(A * a) : A(a) {}
};

// Most derived class, same constructor parameter as the base class.
class C : public B {
public:
    C(A * a) : B(a) {}  /// error: 'class A A::A' is inaccessible
};

int main(int argc, char* argv[])
{
  return 0;
}
注意缺少模板和向量;那些只是转移注意力。此外,对使用原始指针表示歉意;它们只是一种方便的方式,用最少的开销/行李来引入问题。我会使用引用,但这会将其中一个构造函数变成复制构造函数,这感觉不明智

看看B的构造函数的定义。在该定义中,A使用了两次:一次作为参数类型的一部分,一次在初始值设定项列表中。对于后一种情况,A的使用肯定是指正在构造的类的私有基类。问:为什么编译器应该假设前一种情况不也引用私有基类?如果更改了私有基类,那么参数的类型也必然会更改吗?编译器假定是,但您可以在A和B之间引入另一个中间类,这可能会保留参数的类型

据我所知,我没有仔细检查过语言规范,当您处于B的上下文中时,任何对其私有基类的提及都被视为私有信息。您可以将构造函数的声明想象为:B*a。由于不允许C知道B的私有信息,因此不允许调用此构造函数。它根本无法与参数列表匹配,这与参数的类型是在B的私有部分中定义的情况非常相似。幸运的是,可以通过从参数列表中删除对a的提及来避免这种情况

在下文中,唯一的变化是引入和使用typedef


在您的例子中,这样做的另一个好处是为这个符号丰富的std::vector引入了一个较短的同义词。

,因为私有继承意味着私有。继承的一切都是私有的。即使是私有继承类的基类,不管它们是公共的还是非公共的。我的问题是,为什么基类实际上对派生类是不可见的,而不是仅仅阻止它们知道从谁那里继承的,也就是说使内部接口对它们不可用?因为private使得类可以随时更改它从谁那里私下继承的,违反任何API的风险为0%。由于除了类之外,没有任何东西知道它从何处私有继承,因此可以随时更改该类的私有继承。它甚至可以被完全移除。因此,只需要更改类本身。而不是从基cla公开继承
SS,而不是考虑使用虚拟公共继承。现在,虚拟公共类可以从任何子类访问。谢谢,这对我来说是有道理的。但是,我仍然可以在最终用户代码中构造和使用CSSpecializedComposite,在其构造函数中传递cComposite,尽管模板类从cComposite私有继承。让私有基类对派生类完全不可访问似乎有点奇怪,但没有其他人,即最终用户。我相信这是有道理的,我可以让它休息,但它仍然显得很奇怪。谢谢你的回答。我觉得很奇怪,你可以通过引入typedef来规避这个问题,正如我仍然觉得很奇怪,C不能使用公开可用的类型来初始化它的B父类,但是任何构造B实例的人都可以。@Daniel这是语法问题,不是语义问题。C可以使用公共可用类型来初始化B。问题是,如果不使用typedef,B无法表示所需参数是公共可用类型。
// Base class, constructed from a type that involves itself.
class A {
public:
    A(A *) {}
};

// Intermediate class, derives privately from the base class.
class B : private A {
public:
    B(A * a) : A(a) {}
};

// Most derived class, same constructor parameter as the base class.
class C : public B {
public:
    C(A * a) : B(a) {}  /// error: 'class A A::A' is inaccessible
};

int main(int argc, char* argv[])
{
  return 0;
}
class A;
typedef A * special_type;

// Base class, constructed from a type that *indirectly* involves itself.
class A {
public:
    A(special_type) {}
};

// Intermediate class, derives privately from the base class.
class B : private A {
public:
    B(special_type a) : A(a) {}
};

// Most derived class, same constructor parameter as the base class.
class C : public B {
public:
    C(special_type a) : B(a) {}  /// no error!
};

int main(int argc, char* argv[])
{
  return 0;
}