Why does C++ not allow inherited friendship?

Jeff picture Jeff · Aug 25, 2010 · Viewed 56.8k times · Source

Why is friendship not at least optionally inheritable in C++? I understand transitivity and reflexivity being forbidden for obvious reasons (I say this only to head off simple FAQ quote answers), but the lack of something along the lines of virtual friend class Foo; puzzles me. Does anyone know the historical background behind this decision? Was friendship really just a limited hack that has since found its way into a few obscure respectable uses?

Edit for clarification: I'm talking about the following scenario, not where children of A are exposed to either B or to both B and its children. I can also imagine optionally granting access to overrides of friend functions, etc.

class A {
  int x;
  friend class B;
};

class B {
  // OK as per friend declaration above.
  void foo(A& a, int n) { a.x = n; }
};

class D : public B { /* can't get in A w/o 'friend class D' declaration. */ };

Accepted answer: as Loki states, the effect can be simulated more or less by making protected proxy functions in friended base classes, so there is no strict need for granting friendship to a class or virtual method heirarchy. I dislike the need for boilerplate proxies (which the friended base effectively becomes), but I suppose that this was deemed preferable over a language mechanism that would more likely be misused most of the time. I think it's probably time I bought and read Stroupstrup's The Design and Evolution of C++, which I've seen enough people here recommend, to get better insight to these types of questions ...

Answer

Martin York picture Martin York · Aug 25, 2010

Because I may write Foo and its friend Bar (thus there is a trust relationship).

But do I trust the people who write classes that are derived from Bar?
Not really. So they should not inherit friendship.

Any change in the internal representation of a class will require a modification to anything that is dependent on that representation. Thus all members of a class and also all friends of the class will require modification.

Therefore if the internal representation of Foo is modified then Bar must also be modified (because friendship tightly binds Bar to Foo). If friendship was inherited then all class derived from Bar would also be tightly bound to Foo and thus require modification if Foo's internal representation is changed. But I have no knowledge of derived types (nor should I. They may even be developed by different companies etc). Thus I would be unable to change Foo as doing so would introduce breaking changes into the code base (as I could not modify all class derived from Bar).

Thus if friendship was inherited you are inadvertently introducing a restriction on the ability to modify a class. This is undesirable as you basically render useless the concept of a public API.

Note: A child of Bar can access Foo by using Bar, just make the method in Bar protected. Then the child of Bar can access a Foo by calling through its parent class.

Is this what you want?

class A
{
    int x;
    friend class B;
};

class B
{
    protected:
       // Now children of B can access foo
       void foo(A& a, int n) { a.x = n; }
};

class D : public B
{
    public:
        foo(A& a, int n)
        {
            B::foo(a, n + 5);
        }
};