Skip to main content
added 157 characters in body
Source Link
Tony Delroy
  • 106.7k
  • 16
  • 188
  • 265

There are a few reasons people use friend:

  • sometimes granting friendship is actually reasonable, as the public API shouldn't expose some members than need to be compared

  • it's convenient for a lazy programmer to grant access to all the private and protected data members, ensuring you can write the operator implementation without needing to go back to grant access later or use a less obvious/direct public function (that's NOT a good reason, just a lazy one)

  • sometimes granting friendship is actually reasonable, as the public API shouldn't expose some members than need to be compared

  • you can define the operator function inside the class, where any template parameters, typedefs, constants etc. don't need to be explicitly qualified as they would in the surrounding [namespace] scope. That's considerably simpler for those new to C++.

e.g.:

 template <typename T> struct X { friend bool operator==(const X& lhs, const X& rhs) { ... } }; 

...vs... ...struct X as above without ==...

 template <typename T> bool operator==(const X<T>& lhs, const X<T>& rhs) { ... } 
  • in a two-birds-with-one-stone scoop, it makes the function nominally inline, avoiding One Definition Rule complications

None of these are particularly sound reasonsOnly the first reason above is a compelling functional reason for making the operator a friend, rather than making it a non-member function, given the lesser encapsulation and correspondingly higher maintenance burden involved.

There are excellent reasons though to prefer either a friend or non-friend non-member function to a member function thoughprefer either a friend or non-friend non-member function to a member function, as an implicit constructor can then kick in to allow the operator to work with one instance of the class and another value from which a second instance can be constructed:

struct X { X(int); }; bool operator==(const X& lhs, const X& rhs); x == 3; // ok for member or non-member operator== 3 == x; // only works for non-member operator== after implicit X(3) for lhs 

There are a few reasons people use friend:

  • it's convenient for a lazy programmer to grant access to all the private and protected data members, ensuring you can write the operator implementation without needing to go back to grant access later or use a less obvious/direct public function (that's NOT a good reason, just a lazy one)

  • sometimes granting friendship is actually reasonable, as the public API shouldn't expose some members than need to be compared

  • you can define the operator function inside the class, where any template parameters, typedefs, constants etc. don't need to be explicitly qualified as they would in the surrounding [namespace] scope

e.g.:

 template <typename T> struct X { friend bool operator==(const X& lhs, const X& rhs) { ... } }; 

...vs... ...struct X as above without ==...

 template <typename T> bool operator==(const X<T>& lhs, const X<T>& rhs) { ... } 
  • in a two-birds-with-one-stone scoop, it makes the function nominally inline, avoiding One Definition Rule complications

None of these are particularly sound reasons for making the operator a friend, rather than making it a non-member function.

There are excellent reasons though to prefer either a friend or non-friend non-member function to a member function though, as an implicit constructor can then kick in to allow the operator to work with one instance of the class and another value from which a second instance can be constructed:

struct X { X(int); }; bool operator==(const X& lhs, const X& rhs); x == 3; // ok for member or non-member operator== 3 == x; // only works for non-member operator== after implicit X(3) for lhs 

There are a few reasons people use friend:

  • sometimes granting friendship is actually reasonable, as the public API shouldn't expose some members than need to be compared

  • it's convenient for a lazy programmer to grant access to all the private and protected data members, ensuring you can write the operator implementation without needing to go back to grant access later or use a less obvious/direct public function (that's NOT a good reason, just a lazy one)

  • you can define the operator function inside the class, where any template parameters, typedefs, constants etc. don't need to be explicitly qualified as they would in the surrounding [namespace] scope. That's considerably simpler for those new to C++.

e.g.:

 template <typename T> struct X { friend bool operator==(const X& lhs, const X& rhs) { ... } }; 

...vs... ...struct X as above without ==...

 template <typename T> bool operator==(const X<T>& lhs, const X<T>& rhs) { ... } 
  • in a two-birds-with-one-stone scoop, it makes the function nominally inline, avoiding One Definition Rule complications

Only the first reason above is a compelling functional reason for making the operator a friend, rather than making it a non-member function, given the lesser encapsulation and correspondingly higher maintenance burden involved.

There are excellent reasons though to prefer either a friend or non-friend non-member function to a member function, as an implicit constructor can then kick in to allow the operator to work with one instance of the class and another value from which a second instance can be constructed:

struct X { X(int); }; bool operator==(const X& lhs, const X& rhs); x == 3; // ok for member or non-member operator== 3 == x; // only works for non-member operator== after implicit X(3) for lhs 
Source Link
Tony Delroy
  • 106.7k
  • 16
  • 188
  • 265

There are a few reasons people use friend:

  • it's convenient for a lazy programmer to grant access to all the private and protected data members, ensuring you can write the operator implementation without needing to go back to grant access later or use a less obvious/direct public function (that's NOT a good reason, just a lazy one)

  • sometimes granting friendship is actually reasonable, as the public API shouldn't expose some members than need to be compared

  • you can define the operator function inside the class, where any template parameters, typedefs, constants etc. don't need to be explicitly qualified as they would in the surrounding [namespace] scope

e.g.:

 template <typename T> struct X { friend bool operator==(const X& lhs, const X& rhs) { ... } }; 

...vs... ...struct X as above without ==...

 template <typename T> bool operator==(const X<T>& lhs, const X<T>& rhs) { ... } 
  • in a two-birds-with-one-stone scoop, it makes the function nominally inline, avoiding One Definition Rule complications

None of these are particularly sound reasons for making the operator a friend, rather than making it a non-member function.

There are excellent reasons though to prefer either a friend or non-friend non-member function to a member function though, as an implicit constructor can then kick in to allow the operator to work with one instance of the class and another value from which a second instance can be constructed:

struct X { X(int); }; bool operator==(const X& lhs, const X& rhs); x == 3; // ok for member or non-member operator== 3 == x; // only works for non-member operator== after implicit X(3) for lhs