Inaccessible base class despite friendship

Viewed 1535

There are tons of questions regarding this error and all of the answers seem to imply that downcasting is impossible. Only this answer mentions friendship as possible solution, at least as I understand it. However the following code (irrelevant stuff removed for clarity) does not compile:

class C;

class A {
    friend class C;  // this does not help
};

class B : protected A {
    friend class C;  // this does not help either
};

class C {
    public:
    void foo(A* a) {};
};

B b;
C c;

void bar()
{
    c.foo(&b);  // this produces error: class A is an inaccessible base of B
}

Why friendship does not work on a reference? After all, "C" is perfectly capable of calling protected methods of "A" through pointer to "B".

The full error is

prog.cc: In function 'void bar()':
prog.cc:20:13: error: 'A' is an inaccessible base of 'B'
   20 |     c.foo(&b);
3 Answers

Your code is equivalent to this:

B b;
C c;
A * a = &b; // <- This cast produces the error
c.foo(a);

You cannot cast &b as A* since the base class is protected, regardless of the friendship of C.

The problem is that the conversion from B* to A* (the one which requires friendship) does not happen in a member function of C, but in the context of the code containing b and c (i.e. the unrelated function bar()).

It would work fine if you created a member function in C accepting a B*, and then called foo() from within it. That would have the conversion happen within the context of C which has the necessary access rights (thanks to friendship).

In the global scope B is not visible as A, because of protected inheritance.

Only class B itself, classes inherited from B and class C (because the friendship relation) "know" that B is inheriting A. But the rest of the world (including global scope) doesnt'.

So to achieve what you want, you could call

c.foo(&b)

within C scope, for example using some wrapper function, something like (although bad design decision):

#include <iostream>
#include <cstdlib>

class C;


class A {
    friend class C;  // this does not help
};

class B : protected A {
    friend class C;  // this does not help either
};

class C {
public:
    void foo() {
        B b;
        foo(&b);  // this call is OK within C-scope
    }
private:
    void foo(A* /*a*/) {
        std::cout << "C::foo(A* a)\n";
    };
};


int main()
{
    std::cout << "Hello, Wandbox!" << std::endl;
    B b;
    C c;
    //c.foo(&b);  // this produces error: class A is an inaccessible base of B
    c.foo();      // this is calling c.foo(A*) internally
}

or live:

Related