Search code examples
c++inheritanceencapsulationfriendaccess-control

friendship from derived class method to base class members


I would like to know if there's a way to make a method from a derived class a friend of its base class. Something like:

class Derived;
class Base
{
    int i, j;
    friend void Derived::f();
protected:
    Base();
};

class Derived : public Base
{
public:
    void f();
};

The errors I got were:

error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'
error: C2248: 'Base::i' : cannot access private member declared in class 'Base'
see declaration of 'Base::i'
see declaration of 'Base'
error: C2248: 'Base::j' : cannot access private member declared in class 'Base'
see declaration of 'Base::j'
see declaration of 'Base'
error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'

I struggled with it during all the day. Everything I found about friendship use only separated classes, not inheritance.


Solution

  • No there is no direct way : Base needs the definition of Derived::f while Derived also needs the definition of it's Base class.

    But it does not matter, you should not do that, you can, in order of preference :

    • Provide protected accessors in the Base class
    • Make the entire Derived class a friend (not necessary in general)
    • You can use an intermediate helper class which only forward the call of this specific method, and give it friendship :

    Example here:

    class Base;
    class Derived;
    
    class Helper final
    {
        friend class Derived;
    
        public:
            void f(Base* base);
        private:
            Helper() {}
    };
    
    class Base
    {
        int i, j;
        friend class Helper;
    protected:
        Base() {}
    };
    
    class Derived : public Base
    {
    public:
        void f();
    private:
        Helper helper;
    };
    
    void Helper::f(Base* base)
    {
        base->i = 10; base->j = 5;
        std::cout << "Help !" ;
    }
    
    void Derived::f()
    {
        helper.f(this);
    }