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

StackOverflow https://stackoverflow.com/questions/12812334

Question

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?..

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top