Passing a pointer of inaccessible private base type to the derived class method

c++

Solution

Human talk

I 'll start by describing what happens here -- forgive me if you already know this, but it creates necessary context for the follow-up.

The compiler resolves the unqualified `A` to `::C::A` (the result will be the same if you make the change at source level yourself). Since `::C::A` is inaccessible an error message is emitted.

You are proposing that the compiler should detect that `::C::A` is inaccessible and the reference to `A` should then be considered a reference to `::A` as a fallback. However, `::C::A` and `::A` may easily be two entirely different things.

Automatically guessing what should be done here is not only prone to introducing bugs and/or hair-pulling¹, but also completely contrary to the spirit of C++.

Standardese

Confirmation that this behavior is conformant and by-design, directly from the C++11 standard.

§9/2 says:

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

This means that inside the scope of class `C`, `A` is an injected-class-name.

§3.4/3 states that the injected-class-name is a candidate for name lookups:

The injected-class-name of a class is also considered to be a member of that class for the purposes of name hiding and lookup.

§3.4/1 clarifies that the inaccessibility of the base `A` does not prevent the injected-class-name `A` from being considered:

The access rules are considered only once name lookup and function overload resolution (if applicable) have succeeded.

§11.1/5 gives a direct explanation of the exact situation under discussion:

[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 ]

The standard also gives this example, which is equivalent to yours:

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

¹ Imagine what happens if `A` is initially a `public` base, then later becomes `private` during a refactoring. Also imagine that `::A` and `::C::A` are unrelated. You would expect that a call like `a->foo()` (which used to work) would fail because `foo` is no longer accessible, but instead of this the type of `a` has changed behind your back and you now get a "there is no method `foo`" error. Huh?!? And that's of course far from the worst that could happen.

Problem

This code example would describe the language feature I find non-intuitive. ``` class A { public: A() {} }; class B: private A { public: B() {} }; class C: public B { public: C() {} void ProcessA(A* a) { } }; int main() { C c; } ``` Compilation of this code with Apple LLVM version 4.2 on Mac produces an ``` test.cc:16: error: ‘class A’ is inaccessible test.cc:16: error: within this context ``` Replacing `void ProcessA(A* a)` with `void ProcessA(::A* a)` would make it build but I don't understand why should I use absolute class name here. Is it a language feature that is there to avoid certain kind of errors or is it just a dark C++ grammar corner like requirement to put space between angle brackets (`> >`) in templates parametrized with other templates. Thanks!

Original source