【问题标题】:Inheriting a constructor from a private template class in C++从 C++ 中的私有模板类继承构造函数
【发布时间】:2016-12-30 07:49:55
【问题描述】:

为什么D 类可以编译,而C 类不能编译?

class A
{
    public:
        A(int) {}
};

template <class T>
class B : private T // Note: private base class
{
    public:
       using T::T;
};

class C : public B<A>
{
    public:
        C() : B<A>(123) {}  // Error: 'class A A::A' is inaccessible
};                          //         within this context

using BA = B<A>;

class D : public BA
{
    public:
        D() : BA(123) {}  // OK
};

我用 GCC、Clang 和 Visual C++ 进行了测试,它们都是一样的。 将class B : private T 更改为public T 可以解决问题。但为什么? (注意using T::Tpublic。)

【问题讨论】:

  • 我已经添加了“模板”标签来吸引热点。请将任何对“标签垃圾邮件”的批评指向我。
  • 如果你用B(123)替换B&lt;A&gt;(123),它会编译,如果你把C模板化并在任何地方使用B&lt;T&gt;,它也会编译。
  • 这可以证明模板标签的合理性,并且确实在类模板中查找名称略有不同。
  • this,或this

标签: c++ templates language-lawyer


【解决方案1】:

A 类在其范围内包含注入的类名 A(即,A::A 指代 A 类,除非它恰好指代构造函数)。

B继承了这个,所以B范围内的名称A指的是A范围内的注入类名称A。但是,由于AB 的私有基类,所以A 范围内的所有名称在B 内都是私有的。

C 再次继承了这个,但它不能访问这个A,因为它在B 中是私有的。因此错误。请注意,错误实际上是在构造 B&lt;A&gt; 中使用名称 A

BA没有这个问题,因为定义B&lt;A&gt;不在任何类的范围内,所以名称A指的是全局名称A而不是任何注入类-姓名。当然,BA 这个名字是公开的。

您可以通过在 C 中限定名称 A 轻松解决此问题:

class C : public B<A>
{
public:
  C() : B<::A>( 123 ) {}
};

请注意,构造函数继承在那里无效。问题在于访问名称A(注入A并继承于BC),而不是访问构造函数。

【讨论】:

  • 所以,用其他(糟糕的)术语来说,错误是它试图访问(让我说)错误命名空间中的名称A(也就是说,班级B),我错了吗?起首。真的很有趣。
  • @skypjack 是的,就是这样。另一种说法是私有的,因此无法访问的类内名称A,隐藏了(可访问的)全局名称A
  • @Yvette 是的,修复了评论。我已经说过那些话很糟糕! :-)
  • 所以这是问题的简短版本:class A {}; class B : A {}; class C : B { A a1; ::A a2; }; 所以a2 可以,但a1 不行。我不敢相信我以前从未遇到过这种情况......
  • @Barnett 真的,你多久开始使用私有继承?
猜你喜欢
  • 1970-01-01
  • 2016-03-04
  • 2013-09-04
  • 1970-01-01
  • 2019-12-14
  • 2017-10-20
  • 2013-05-21
  • 1970-01-01
  • 2018-09-29
相关资源
最近更新 更多