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

后端 未结 1 567
终归单人心
终归单人心 2020-12-20 12:11

This code example would describe the language feature I find non-intuitive.

class A {
public:
  A() {}
};

class B: private A
{
public:
  B() {}
};

class C:         


        
相关标签:
1条回答
  • 2020-12-20 13:08

    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.

    0 讨论(0)
提交回复
热议问题