0

Though there are many posts about making overloaded operator functions friend or member, I still can not decide on either. I am implementing templated matrix class mainly for arithmetic operations and I have written overloaded operator functions both ways. What should be the criterion for making them friend or otherwise? Thanks

Renu
  • 29
  • 5
  • 1
    Not I duplicate (I think) but this contains some good rules/guidelines/discussion [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading). My take this is (1) least surprise for the user and (2) member functions should operate on the object, if they return a new object then make them non-members. – Richard Critten Jun 06 '23 at 14:08
  • 1
    There is no supreme leader of C++ that sits on a throne and blesses selected implementation techniques and condemns all others. In this kind of a situation an intelligent decision is made by fully understanding the pros and cons of each alternative, and then picking the best alternative that's specific to the classes, templates, and the application code. – Sam Varshavchik Jun 06 '23 at 14:10
  • 1
    One difference is that a member always has `this` as the leftmost parameter, while a friend can have a different type. That's why `operator<<(ostream&, my_class)` cannot be a member of the class. – BoP Jun 06 '23 at 14:12
  • My rule of thumb: friend is a violation of encapsulation but it's sometimes a necessary one. Thus, first I think my designs in order not to use it. If I must expose my class internals to some function or other class, I try first a [keyring pattern](https://stackoverflow.com/questions/3217390/clean-c-granular-friend-equivalent-answer-attorney-client-idiom/3218920#3218920) (not sure if its the best link). only in last resort I use ```friend```. – Oersted Jun 06 '23 at 14:41
  • perhaps this [link](https://stackoverflow.com/questions/3217390/clean-c-granular-friend-equivalent-answer-attorney-client-idiom) for fine-grain friendness. – Oersted Jun 06 '23 at 14:42

1 Answers1

0

This is mostly the domain of preferences and guidelines, some of which have been mentioned in the comments, some more are listed in my go-to recommendation C++ Core Guidelines.

There are some hard constraints, though. One in particular may be relevant to you: suppose you want to allow multiplication with scalar numbers. Fundamental types do not even have member functions, so if they can appear on the left-hand side you can only define the operator as a non-member. But the same applies to classes you cannot modify yourself, like std::complex.

If that operator additionally needs access to details of your class you do not want to make public, then the only practical choice is to make it a friend. This actually protects encapsulation!

Apart from these constraints, the friend declaration has some benefits. It allows you to define a non-member function inline within the class, without having to repeat the potentially complicated template header out-of-line. Such an inline friend is also known as a "hidden friend", because it is hidden from ordinary name lookup. Now we are getting quite technical, but this can nonetheless significantly affect compilation speed.

For some example code, my preference would be to implement the example of scalar multiplication like this:

template<number T, ...>
class Matrix
{
public:
    Matrix& operator*=(T const& rhs)
    { /* the actual operation */ }

    friend Matrix operator*(Matrix lhs, T const& rhs)
    {
        lhs *= rhs;
        return lhs;
    }

    friend Matrix operator*(T const& lhs, Matrix rhs)
    {
        return rhs * lhs;
    }
};

The name number here is just a stand-in for a suitable concept. There is currently no concept in the standard library that includes non-fundamental arithmetic types, so you would have to source your own to allow for complex numbers. Note that the operator*s could be regular non-members in this example, I just find it more convenient and readable this way.

sigma
  • 2,758
  • 1
  • 14
  • 18