The A friend ad creates a strong relationship between friend and trust:
- he associates Friendly with the Trusting view as he has gained full access to its internal functions.
- this means that Friendly agrees to support Trusting class invariants
Therefore, it seems good practice to clearly define the exact scope of what inheritance failed to achieve: a leak has occurred.
True, true that inheritance is not even necessary. There are actually two alternatives, depending on what kind of friendship you are trying to achieve. They cover any scenario that I have ever encountered.
Proxy friendly
In your example, derivatives from Friendly can simply go to Trusting through Friendly , which allows you to manage operations that occur on Trusting in a limited set of locations.
class Trusting { friend class Friendly; }; class Friendly { protected: void modifyTrusting(); };
A modifyTrusting implementation may mean virtual calls (hooks) to customize the behavior, but regardless of these bindings, it is up to Friendly to ensure that class invariants are not broken.
Not so trust
In this case, Trusting opens only part of its interface through a locked method and provides a key for Friendly . Friendly can alternatively provide a key to classes in which it trusts, but this does not really matter ... In any case, Trusting ensures that its invariants are not violated, and the key is just a mechanism to reduce the impact of the method.
class Key { friend class Friendly; Key() {} ~Key() {} }; class Trusting { public: void doSomething(Key const&); }; class Friendly { protected: Key const& key() const; };
I must admit that I am really part of this last method and use it regularly because it limits the exposure of Friendly details of the implementation of Trusting . It also clearly documents which parts of Trusting our expensive access are Friendly .
source share