嵌套类继承的错误

Error with nested class inheritance

本文关键字:错误 继承 嵌套      更新时间:2023-10-16
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 {};

这是正确的行为,如果是的话,为什么?

首先,我认为这是因为CB私下继承,这将隐藏基本类。但是,如果我消除了"中间人"类B,然后使用以下方式:

class A {};
class C : private A
{
public:
    class D : private A {};
};

错误消失了。

引用 cppReference

根据不合格的名称查找的名称,可能是 通过合格的名称查找

访问

考虑到这一点,让我们看看第一个示例的不合格名称查找将如何工作:

class A {};
class B : private A {};
class C : private B
{
public:
    class D : private A {}; // Error here
};
  1. AC的范围内查找。如果在那里定义它,就没有问题。
  2. 它弄清楚A是由其基础(私有)类B私下继承的,因此引发了编译器错误。Clang说:
    注意:在这里受私人继承约束:B类:私人A {};

再次,按照报价应起作用,如果您使用完全合格的名称,就像您显示的那样

class D : private ::A {};

,至于您的上一个示例:

class A {};
class C : private A
{
public:
    class D : private A {};
};

它起作用是因为,该名称查找适用于同一类的所有名称。再次引用cppreference:

班级的所有成员(成员功能的主体,初始化器 成员对象和整个嵌套类定义) 对于可以访问的所有名称。

这是名称查找期间的范围问题:

  • 当您使用::A时,这是一个完全合格的名称,因此您明确地参考了全局名称空间并从那里挑选A

  • 当您从A继承时,C(让我说)看到A,您可以直接参考带有不合格名称的A名称。

  • 当您从B继承时,C SEES BA在其范围中是私有的。它是私人的,但存在。因为A是一个不合格的名称,并且首先在该范围中寻找它,所以它恰好被发现和无法访问,因此错误。

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的公共和受保护的成员。

是理解的关键部分,在其他答案中没有明确阐明,这是以下内容:

班级的名称注入了类的范围。

也就是说,如果您有

class A {};

然后,您不仅可以用名称::A,而且可以使用名称A::A参考类A。请注意,尽管描述了同一类,但它们是不是,就像它们在不同的范围中一样。

现在,当在A的范围或直接或间接从A派生的类范围内时,无限制的查找将找到A::A而不是::A(除非A::A本身是由另一个名称隐藏的)。

)。 )。

此外,与其他某些语言不同,C 不会从无法访问它们的范围内的scopes中 hide 私有名称,而是仅使用访问说明符,仅将访问说明符为使用使用 name 。此外,这些权限与名称约束,而不是指定的实体(在这种情况下为类)。

因此,在您的代码中,在A的不合格查找中,编译器找到隐藏名称::A的名称C::B::A::A,然后检查访问权限并在当前上下文中找到此名称是私有的,因为它是范围中的名称。C::B::A的CC_34无法从C中访问,因为AB的私有基类。

类D:private :: a {};当您从B继承时,C看到B,A在其范围中是私人的。它是私人的,但存在。因为A是一个不合格的名称,并且首先在该范围中寻找它,所以它恰好被发现和无法访问,因此错误。