Why a simple mention of base pointer/reference in

2020-05-26 06:09发布

问题:

struct B {};
struct D : private B {
  B* fun () { return new D; }  // ok
}
struct DD : public D {
  B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
};

This error seems unreasonable to me. If we can use simple B* in global scope then why not in its privately derived classes? g++ demo.

We are Not trying to convert DD* to B*, which is forbidden by the language rules (this, this, this are related questions).
Note that, if I change B* foo() to int foo(), things go fine.

回答1:

So apparently the compiler thinks B is referring to the private constructor of B rather than the type.

Qualifying B apparently fixes that error:

class B* foo () { return 0; }

or this:

::B* foo () { return 0; }

I don't know why that's happening, but maybe this will help.


Update: maybe it's related to 11.2.4 of standard? The only problem is that my standardese isn't good enough to fully understand it.

(sorry for the image, copy/pasting isn't working for me)



回答2:

A quick look-up for injected-class-name in the Standard yields:

§11.1 [class.access.spec]

5/ [ Note: In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared. —end note ]

[ Example:

class A { };
class B : private A { };
class C : public B {
    A *p; // error: injected-class-name A is inaccessible
    ::A *q; // OK
};

—end example ]

I believe this is eerily close to your example ;)


Note clang 3.0's stack, which is slightly more explicit:

$ clang++ -fsyntax-only test.cpp
test.cpp:6:5: error: 'B' is a private member of 'B'
    B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
    ^
test.cpp:2:12: note: constrained by private inheritance here
struct D : private B {
           ^~~~~~~~~
test.cpp:1:8: note: member is declared here
struct B {};
       ^
1 error generated.

Here we see that B is accessed through D, instead of directly picked up in the global namespace.



回答3:

My best guess is that it's not forbidden, C++ simply doesn't see the B type inside that statement or in better terms the label B means nothing.

Some good read about

  • http://eli.thegreenplace.net/2012/02/06/dependent-name-lookup-for-c-templates/
  • https://stackoverflow.com/a/7376212/1797612
  • List of C++ name resolution (and overloading) rules