2016-08-23 133 views
46

为什么类D编译,但C类不?从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

+0

我已经添加了“模板”标签来吸引人物。请直接批评我的“标记垃圾邮件”。 – Bathsheba

+0

这将证明模板标签,实际上类模板中的名称查找略有不同。 – MSalters

回答

42

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

类继承B此,所以B范围内的名称A指注射类名AA范围。但是,由于AB的私有基类,所以在A范围内的所有名称在B内都是私有的。

C再次继承此,但它不能访问此A,因为它在B内是私人的。因此错误。请注意,该错误实际上是在构造B<A>中使用名称A

BA没有这个问题,因为定义B<A>是不是在任何类别的范围,故得名A指的是全局名称A,而不是任何注入的类名。当然,名称BA是公开的。

您可以轻松地在C限定名称A解决这个问题:

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

注意,构造继承了有没有效果。问题是访问名称A(注入A并继承于BC),而不能访问构造函数。

+1

所以,在其他(穷人)术语中,错误是它试图访问(让我说)_wrong_命名空间(即类“B”)中的名称'A',我错了吗?起首。十分有趣。 – skypjack

+0

访问该类的私人会员@skypjack –

+0

@skypjack是的,就是这样。另一种说法是,私有的,因此无法访问的类名称“A”隐藏(可访问的)全局名称“A”。 – Angew