Patrik
Patrik

Reputation: 413

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.

Upvotes: 2

Views: 1337

Answers (3)

quantdev
quantdev

Reputation: 23813

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);
}

Upvotes: 2

Keith
Keith

Reputation: 6834

One approach for this kind of problem is to apply the rule "if it's a thing, then it's a class."

@quantdev solution is on those lines.

Based on the comment:

assuming that I have two classes both derived from base class and having an identical private member. Why not saving some codes by putting that member in the base class and providing a friend access to both derived classes that need the member. Assuming that other derived classes won't be able to access that member at all. That's what I'm trying to achieve

[I know that this does not answer the specified question, but may be what you need.]

I'd solve that by factoring the common element into an intermediate class:

class Base
{
public:
    Base();
    virtual ~Base() = 0;
};

class Derived : public Base
{
public:
    void f()
    {
        i = 1;
    }
private:
    int i, j;
};

class Foo : public Derived
{};

class Bar : public Derived
{};

class Fred : public Base
{};

Upvotes: 1

Turix
Turix

Reputation: 4490

I don't know if it is possible to do exactly what you want (although it seems to me like it should be) -- and I'd be interested to see other answers that show how if it is -- but there are a few other ways to achieve what you want. I assume you are asking about this situation in general -- that is, you are also interested in the case where there can be many different derived classes, not all of which need, no should have access to the private fields of Base (otherwise you should make these fields protected of course).

First, the easiest thing to do would be to make Derived a friend class to Base, although this feels like a hack (in part because it doesn't allow for any encapsulation of Base with respect to Derived) and is definitely sub-optimal here.

In my opinion, a somewhat better approach in terms of encapsulation would be to make an external "free" (non-member) function that is a friend to Base (and potentially Derived if you need that too). This gets around the circular compiler error, but unfortunately still loses the conceptual semantics of being an "operation on Derived".

Upvotes: 0

Related Questions