class A {};
class B : private A {};
class C : private B
{
public:
class D : private A {}; // Error here
};
此代码提供以下错误(在VS 2013中):
nested.cpp(8):错误C2247:'A'无法访问,因为'B'使用'private'继承'A'
如果我像这样改变D
的定义,它就会得到修复:
class D : private ::A {};
这是正确的行为,如果是这样,为什么?
起初我认为这是因为C
从B
私下继承,这会隐藏基类。但是,如果我消除“中间人”类B
并使用它:
class A {};
class C : private A
{
public:
class D : private A {};
};
错误消失了。
答案 0 :(得分:18)
引自 cppreference :
根据非限定名称查找的私有名称,可能是 可通过限定名称查询访问
考虑到这一点,让我们看看非限定名称查找如何适用于第一个示例:
class A {};
class B : private A {};
class C : private B
{
public:
class D : private A {}; // Error here
};
A
范围内查找C
。如果在那里定义,就没有问题。A
是由它的基础(私有)类B
私有继承的,因此会引发编译错误。
Clang说:note: constrained by private inheritance here: class B : private A {};
同样,根据引用它应该有效,如果你使用完全限定名称,就像你已经显示
class D : private ::A {};
至于你的上一个例子:
class A {};
class C : private A
{
public:
class D : private A {};
};
它起作用,因为名称查找适用于属于同一个类的所有名称。再次引用cppreference:
一个类的所有成员(成员函数体,初始化函数) 成员对象和整个嵌套类定义)具有访问权限 一个类可以访问的所有名称。
答案 1 :(得分:13)
这是名称查找过程中的范围问题:
当您使用::A
时,它是一个完全限定的名称,因此您明确引用全局命名空间并从那里选择A
。
当您从A
继承时,C
(让我说)看到A
,您可以直接引用A
中的C
名称用不合格的名字。
当您从B
继承时,C
看到 B
,A
在其范围内是私有的。它是私有的,但它存在。因为A
是一个非限定名称,并且首先在该范围内查找,所以它恰好被发现并且无法访问,因此错误。
答案 2 :(得分:7)
来自cppreference的示例:
class A { };
class B : private A { };
class C : public B {
A* p; // error: unqualified name lookup finds A as the private base of B
::A* q; // OK, qualified name lookup finds the namespace-level declaration
};
使用私有继承,基类的public和protected成员将成为派生类的私有成员。
class B : private A {};
class C : private B
{
public:
class D : private A {}; // Error because all members of A is private to B so what
//would be the use of this private inheritance if you can't access any of A's member.
};
虽然
class D :private ::A {};
有效,因为A的成员直接从全局命名空间中获取,使D
能够访问A
的公共和受保护成员。
答案 3 :(得分:4)
理解的一个关键部分,在其他答案中没有明确说明,如下:
将一个类的名称注入到类中。范围。
也就是说,如果你有
class A {};
然后,您不仅可以通过名称A
来引用课程::A
,还可以使用名称A::A
来引用课程A
。请注意,尽管描述了相同的类,但它们不是的名称相同,因为它们位于不同的范围内。
现在,当A
范围内或直接或间接来自A::A
的类时,非限定查询会找到::A
而不是A::A
(除非A
本身隐藏了另一个名字。)
此外,与其他一些语言不同,C ++不会从无法访问它们的范围隐藏私有名称,而只使用访问说明符作为使用名称的权限。而且,这些权限绑定到名称,而不是命名实体(在本例中为类)。
因此,在您的代码中,在C::B::A::A
的非限定查找中,编译器会找到隐藏名称::A
的名称C::B::A
,然后检查访问权限并发现此名称是私有的当前上下文,因为它是C
范围内的名称,无法从A
内访问,因为B
是create table Hotel(id_Hotel INT, id_Manager INT...)
的私有基类。
答案 4 :(得分:2)
D类:私人:: A {}; 当您从B继承时,C看到B,A在其范围内是私有的。它是私有的,但它存在。因为A是一个非限定名,并且首先在该范围内查找,所以它恰好被发现并且无法访问,因此错误。