11.2 Friends

11.2.1 Do not use friend declarations

Friend declarations reduce encapsulation, resulting in code that is harder to maintain.

class C
{
public:
C & operator += (C const & other);
                 
friend C const operator + (C const &, C const & lhs); // @@- Non-Compliant -@@
};
               
class D
{
public:
D & operator += (D const & other);
};
               
D const operator + (D const & rhs, D const & lhs) // @@+ Compliant +@@
{
D result (rhs);
result += (lhs);
return result;
}

The following example demonstrates an additional complexity when adding friendship for functions that include universal reference parameters. In such cases an explicit declaration is required for all combinations of the lvalue reference and rvalue reference versions.

template <typename T, typename S>
void foo (T && t, S && s)
{
t.foo ();
}
               
class A
{
private:
void foo ();
               
friend void foo(A &, A &);
friend void foo(A &, A&&);
friend void foo(A&&, A &);
friend void foo(A&&, A&&);
};
               
int main ()
{
A a;
foo(a, a);
foo(a, A());
foo(A(), a);
foo(A(), A());
}

Exception

In some cases friend declarations are part of the class interface, for example:

  • serialization via stream input and output operators (operator << and operator >>)
  • factory functions requiring access to private constructors
  • an iterator class

For Example:

# include <cstdint>
class C
{
public :
C (C const &) = default ;
C (C &&) = default ;
private :
C ( int32_t );
friend C createClassC ( int32_t );
};
C createClassC ( int32_t i)
{
// pre condition check on ’i’
return C(i);
}

References

  • HIC++ v3.3 – 3.4.4

Click here for references