Whether to go for a member function or friend function when the function is supposed to change state of object?
Asked Answered
B

3

8

In the book The C++ Programming Language, by Bjarne Stroustrup, the author introduces a class Matrix which has to implement a function inv(). In section 11.5.1, he talks about two possibilities of doing that. One is to make a member function and other is to make a friend function inv(). Then towards the end of section 11.5.2, where he talks about making the choice of whether to use a friend or a member function, he says:

If inv() really does invert Matrix m itself, rather than returning a new Matrix that is the inverse of m, it should be a member.

Why is it so? Can't a friend function change the state of the Matrix and return the reference to that matrix? Is it because of the possibility of passing a temporary matrix when we call the function?..

Beabeach answered 10/10, 2012 at 5:11 Comment(5)
Probably to have more clearly defined encapsulation of functionality inside the object instead of spread about in different friend functions.Loreenlorelei
Related https://mcmap.net/q/676865/-when-should-i-prefer-non-member-non-friend-functions-to-member-functionsJaf
I think answers worthy of upvotes here should point out the actual differences between member functions and non-member friends and explain how those differences would contribute to making a decision, not wave everything away with "because it provides more/less encapsulation".Jaf
@R.MartinhoFernandes, that's a good point, I guess we're assuming the OP knows why more encapsulation is better. Nicolas hints at what you're suggesting in his answer, that's partly why I upvoted it. If we now update our answers with what you're suggesting, then perhaps we shouldnt deserve the upvote. Perhaps it would be better if you make an answer explaining what you suggest :)Willetta
@Willetta my point is that there is no more (nor less) encapsulation anywhere in sight (writing an answer...)Jaf
J
13

To be honest, I think the only reasons to make such a decision are syntactic convenience and tradition. I'll explain why by showing what are (not) the differences between the two and how these differences matter when making a decision.

What differences are there between non-member friend functions and public member functions? Not much. After all, a member function is just a regular function with a hidden this parameter and access to the class's private members.

// what is the difference between the two inv functions?
// --- our code ---
struct matrix1x1 { // this one is simple :P
private:
    double x;
public:
    //... blah blah
    void inv() { x = 1/x; }
    friend void inv(matrix1x1& self) { self.x = 1/self.x; }
};
matrix1x1 a;

// --- client code ---

// pretty much just this:
a.inv();
// vs this:
inv(a);

void lets_try_to_break_encapsulation(matrix1x1& thingy) {
    thingy.x = 42; // oops, error. Nope, still encapsulated.
}

They both provide the same functionality, and in no way do they change what other functions can do. The same internals get exposed to the outside world: there's no difference in terms of encapsulation. There's absolutely nothing that other functions can do differently because there's a friend function that modifies private state.

In fact, one could write most classes with most functions as non-member friend functions (virtual functions and some overloaded operators must be members) providing the exact same amount of encapsulation: users cannot write any other friend function without modifying the class, and no function other than the friend functions can access private members. Why don't we do that? Because it would be against the style of 99.99% of C++ programmers and there's no great advantage to be taken from it.

The differences lie in the nature of the functions and the way you call them. Being a member function means you can get a pointer to member function from it, and being a non-member function means you can get a function pointer to it. But that's rarely relevant (especially with generic function wrappers like std::function around).

The remaining difference is syntactic. The designers of the D language decided to just unify the whole thing and say that you can call a member function directly by passing it an object like inv(a), and call a free function as a member of its first argument, like a.inv(). And no class suddenly got badly encapsulated because of that or anything.1

To address the particular example in the question, should inv be a member or a non-member? I'd probably make it a member, for the familarity argument I outlined above. Non-stylistically, it doesn't make a difference.


1. This is unlikely to happen in C++ because at this point it would be a breaking change, for no substantial benefit. It would, for an extreme example, break the matrix1x1 class I wrote above because it makes both calls ambiguous.

Jaf answered 10/10, 2012 at 6:10 Comment(3)
You've provided one quite contained case of a friend function, but what about when someone makes a class a friend? It could be argued that that does indeed reduce or even break encapsulation.Willetta
For what is worth the question is about member functions vs friend functions (it doesn't make any sense at all for friend classes). If it were about classes I'd still require one example of that to accept that claim anyway.Jaf
Good point. My answer was referring to friends in general (class and function). The STL uses friend functions in several places, but I dont think it uses friend classes.Willetta
M
0

The encapsulation philosophy inherent to OOD (which C++ tries to promote) dictates that object state can only be modified from within. It is syntactically correct (the compiler allows it) but it should be avoided.

It is error prone to let elements throughout the system alter each other without using predefined interfaces. Object storage and functionality could change and looking around for code (that might be huge) that uses a specific part of an object would be a nightmare.

Mythical answered 10/10, 2012 at 5:24 Comment(0)
W
0

There are two opposing arguments regarding using friends:

One side says friends reduces encapsulation because now you're letting external entities access the internals of a class and the internals should only be modified by member methods.

The other side says that friends could actually increase encapsulation, since you can give access to the internals of a class to a small set of external entities, thus obviating the need to make internal class attributes public to everyone so these external entities can access/manipulate them.

Both sides could be argued, but I tend to agree with the first option.

As for your question, its as PherricOxide mentioned in his comment: If the internal attributes of a class need to be modified, its better that that be done by a member method, thus enforcing encapsulation. This is inline with the first option mentioned above.

Willetta answered 10/10, 2012 at 5:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.