Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inaccessible base class despite friendship

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);
like image 210
Maple Avatar asked Jun 19 '19 18:06

Maple


People also ask

Which of the members are directly accessible from a friend of a class?

As we know a private member is inaccessible (not just private) in derived classes while public and protected are directly accessible there. If a class declares another class as a friend then the latter has full-access to the members of the first.

Is friendship inherited by child classes?

Inheritance and friendship in C++ In C++, the friendship is not inherited. It means that, if one parent class has some friend functions, then the child class will not get them as friend.

Which of the following Cannot be inherited from the base class?

Constructor cannot be inherited but a derived class can call the constructor of the base class.

What can be inherited from base class?

Inheritance enables you to create new classes that reuse, extend, and modify the behavior defined in other classes. The class whose members are inherited is called the base class, and the class that inherits those members is called the derived class. A derived class can have only one direct base class.


Video Answer


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.

like image 54
Gilles-Philippe Paillé Avatar answered Oct 19 '22 05:10

Gilles-Philippe Paillé


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).

like image 43
Angew is no longer proud of SO Avatar answered Oct 19 '22 04:10

Angew is no longer proud of SO


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:

like image 1
StPiere Avatar answered Oct 19 '22 06:10

StPiere