嵌套类继承出错

use*_*015 25 c++ inheritance visual-studio-2013

class A {};
class B : private A {};
class C : private B
{
public:
    class D : private A {}; // Error here
};
Run Code Online (Sandbox Code Playgroud)

此代码提供以下错误(在VS 2013中):

nested.cpp(8):错误C2247:'A'无法访问,因为'B'使用'private'继承'A'

如果我改变这样的定义,它会得到修复D:

class D : private ::A {};
Run Code Online (Sandbox Code Playgroud)

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

起初我以为这是因为C私下继承B会隐藏基类.但如果我消除了"中间人"类B并且只使用它:

class A {};
class C : private A
{
public:
    class D : private A {};
};
Run Code Online (Sandbox Code Playgroud)

错误消失了.

Aru*_*nmu 18

引用来自cppreference:

根据非限定名称查找的私有名称,可以通过限定名称查找来访问

考虑到这一点,让我们看看非限定名称查找如何适用于第一个示例:

class A {};

class B : private A {};

class C : private B
{
public:
    class D : private A {}; // Error here
};
Run Code Online (Sandbox Code Playgroud)
  1. A在范围内查找C.如果在那里定义,那就不会有问题.
  2. 它的数字A是由它的基类(私有)类私有继承的B,因此会抛出编译器错误.Clang说:
    note: constrained by private inheritance here:
    class B : private A {}; 

再次,根据它应该起作用的引用,如果你使用完全限定的名称,就像你已经显示的那样

class D : private ::A {};
Run Code Online (Sandbox Code Playgroud)

至于你的最后一个例子:

class A {};

class C : private A
{
public:
    class D : private A {};
};
Run Code Online (Sandbox Code Playgroud)

它的工作原理是,名称查找适用于属于同一个类的所有名称.再次引用cppreference:

类的所有成员(成员函数体,成员对象的初始化器和整个嵌套类定义)都可以访问类可以访问的所有名称.


sky*_*ack 13

这是名称查找过程中的范围问题:

  • 当您使用::A它时,它是一个完全限定的名称,因此您明确地引用了全局命名空间并A从那里获取.

  • 当你继承A,C(让我说)看到A,您可以直接引用A名称中C使用不合格的名称.

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


Sau*_*ahu 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
};
Run Code Online (Sandbox Code Playgroud)

使用私有继承,基类的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.
};
Run Code Online (Sandbox Code Playgroud)

class D :private ::A {}; 
Run Code Online (Sandbox Code Playgroud)

因为A的成员直接从全局命名空间中获取,所以可以D访问A公共成员和受保护成员.