c++name-lookupprivate-inheritance

Private inheritance, return reference to static member of base class


I have a simple question regarding inheriting from a class which privately inheriting of a base class, i.e. we have

class Base {};
class Heir: private Base {};
class HeirsHeir : public Heir {};

In understand that HeirsHeir cannot access anything of 'its' Base. In particular, it cannot have a method returning a Base & reference to itself. But why can't it return a reference to another Base object? So why does the following code not compile:

class Base {};
class Kid : private Base {};
Base instance;
class Grandkid : public Kid
{
    const Base &GetInstance  () const
    { return instance; }
};

At least my compiler (MinGW 5.3, i.e. gcc for Windows) gives

error 'class Base Base::Base' is inaccessible at {}; 
error: within this context const Base &getInstance () const

For my understanding this doesn't make sense as I do not call the constructor of Base at this point, but return a reference (to a Base instance).

Note that the error can be fixed by using

const ::Base &GetInstance  () const
{ return instance; }

which is surely linked to C++03 §11.2/3 (see [C++ private inheritance and static members/types)

Note: A member of a private base class might be inaccessible as an inherited member name, but accessible directly.

But I do not understand why this is necessary. Can somebody explain it?


Solution

  • The name lookup finds the injected-class-name Base which is injected into Base (and thus inherited by GrandKid). This is correct, since the injected-class-name is in a closer scope than the namespace-scope name of the class. However, this injected-class-name is not accessible to GrandKid because it's private in Kid.

    In the compiler's error message, Base::Base doesn't refer to the constructor, but to the class name Base injected into Base. Note that when the context in which it is used forces the name to be interpreted as a type, you can actually use Base::Base legally, like in this valid, but vile code:

    class Foo {};
    
    std::vector<Foo::Foo::Foo::Foo> v;
    

    [Live example]

    However, when the context in which Base::Base is used would allow referring to a function, it is taken to resolve to the constructor and not to the class name (C++11 [class.qual] 3.4.3.1/2)