As I was recently reviewing some of the concepts of C++, this question popped up. So what is the difference between member operators and nonmember operators?
Well it turns out there isn’t much of a difference as far as the language is concerned (except the additional argument of the object type in the nonmember function implementation). Given an operation on a user-defined type, either the presence of a member or a nonmember operator would be enough. So then why does the language provide the option of choosing between the two?
The answer turned out to be simple.
A member operator is typically used when
- the operator modifies the value of the object to which it is applied, requring it access to the object’s data members. Or,
- the operator requires access to the object’s internal state, represented by data members which are not otherwise accessible (through a public method).
In all other instances a nonmember operator is to be preferred. This ensures that there’s that much less chance of the object’s data members getting inadvertently modified (which is only possible from a member method) and at the same time not increasing the size of the object. Refer to 11.3.1, C++ Programming Language, B.Stroustrup.
Examples for operators that explicitly modify the state of an object are +=, +-, <<=, etc. A real world code example:
class complex {
double real, imag;
public:
...
complex& operator+=(complex& c);
};
Examples for the second case where member operators are necessary can also be found in the standard library. The basic_ostream template class declares the '<<' operator for all basic datatypes except 'char' (actually template parameter 'Ch') as member operators. This is because output of the character representation of these datatypes (which is what the inserter operator accomplishes) depend on the various state information as set by the user. Examples for these state include output number system (decimal, octal or hexadecimal), precision, width, display of '+' sign, etc.
However, the output of a 'char' does not require access to any state information. Consequently, '<<' for various 'char' types (signed, unsigned, char*, etc) are achieved through a nonmember function such as:
template<class Ch, class Tr>
basic_ostream<Ch, Tr>& operator<<(basic_ostream<Ch, Tr>&, Ch);
So the golden rule to learn is that if an operator can be implemented as a nonmember function, that is the best way to go as it would have the least impact on the object concerned.
