嵌套类继承错误
Posted
技术标签:
【中文标题】嵌套类继承错误【英文标题】:Error with nested class inheritance 【发布时间】:2016-12-09 07:17:49 【问题描述】: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”使用“私有”从“A”继承
如果我像这样更改D
的定义,它会得到修复:
class D : private ::A ;
这是正确的行为吗?如果是,为什么?
起初我以为是因为C
私下继承自B
会隐藏基类。但如果我消除“中间人”类B
并使用它:
class A ;
class C : private A
public:
class D : private A ;
;
错误消失了。
【问题讨论】:
编译器告诉你原因。 因为'B'使用'private'继承自'A',而不是因为C私有地继承自B。 @n.m.好吧,这并没有告诉我太多。毕竟,我使用的是全局命名空间中的一个类,而不是某个东西的成员。无论如何,感谢答案,我现在明白了。 名称是从内向外搜索的。找到名称后,搜索停止。然后检查可访问性。在您的情况下,搜索路径是 C>B>A。 B>A 因为私有继承而被阻塞,A 不可访问。这是编译器告诉你的。 A 也存在于全局范围内,并且是同一个 A,是无关紧要的。 @n.m.不,编译器并没有告诉我所有这些...... 【参考方案1】:引用自cppreference:
根据非限定名称查找的私有名称,可能是 可通过限定名称查找访问
考虑到这一点,让我们看看第一个示例的非限定名称查找如何工作:
class A ;
class B : private A ;
class C : private B
public:
class D : private A ; // Error here
;
-
在
C
的范围内查找A
。如果在那里定义,就不会有问题。
它发现A
是由它的基(私有)类B
私有继承的,因此会引发编译器错误。
Clang 说:注意:此处受私有继承的约束: B类:私人A ;
再次,根据报价,如果您使用完全限定名,就像您展示的那样,它应该可以工作
class D : private ::A ;
至于你的最后一个例子:
class A ;
class C : private A
public:
class D : private A ;
;
之所以有效,是因为名称查找适用于属于同一类的所有名称。再次引用 cppreference:
类的所有成员(成员函数的主体, 成员对象和整个嵌套类定义)可以访问 类可以访问的所有名称。
【讨论】:
大概算出来了?答案应该是一个答案,而不是另一个潜在的问题。【参考方案2】:这是名称查找期间的范围问题:
当您使用 ::A
时,它是一个完全限定名称,因此您明确引用全局命名空间并从那里选择 A
。
当您从A
继承时,C
(让我说)看到A
,您可以直接在C
中使用非限定名称引用A
名称。
当您从 B
继承时,C
看到 B
和 A
在其范围内是私有的。它是私人的,但它存在。因为A
是一个非限定名称,并且首先在该范围内查找,所以它恰好被发现且无法访问,因此出现错误。
【讨论】:
【参考方案3】:来自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
;
通过私有继承,基类的公共和受保护成员成为派生类的私有成员。
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
的公共和受保护成员。
【讨论】:
【参考方案4】:其他答案中没有明确说明的理解的关键部分如下:
类的名称被注入到类的作用域中。
也就是说,如果你有
class A ;
那么您不仅可以通过名称::A
还可以通过名称A::A
来引用类A
。请注意,尽管描述的是同一个类,但它们不同名,因为它们在不同的范围内。
现在,当在 A
或直接或间接派生自 A
的类的范围内时,不合格的查找将找到 A::A
而不是 ::A
(除非 A::A
本身被另一个名称隐藏)。
此外,与其他一些语言不同,C++ 不会隐藏您无法访问它们的作用域中的私有名称,而是仅将访问说明符用作使用名称的权限 .此外,这些权限绑定到名称,而不是命名实体(在本例中为类)。
因此,在您的代码中,在对 A
进行非限定查找时,编译器会找到名称 C::B::A::A
,它隐藏了名称 ::A
,然后检查访问权限并发现该名称在当前上下文中是私有的,因为它是C::B::A
范围内的名称,不能从C
中访问,因为A
是B
的私有基类。
【讨论】:
【参考方案5】:类 D : 私有 ::A ; 当您从 B 继承时,C 看到 B 并且 A 在其范围内是私有的。它是私人的,但它存在。因为 A 是一个非限定名称,并且首先在该范围内查找它,所以它恰好被发现且无法访问,因此出现错误。
【讨论】:
以上是关于嵌套类继承错误的主要内容,如果未能解决你的问题,请参考以下文章