For most kinds of numerical data, the addition operation is commutative: the result doesn't depend on the operands' order. To make the fraction addition operation, operator+, fully commutative, it must function correctly in three different cases. Let f1 and f2 be two fraction objects, and i be an integer:
In the previous section, we created two overloaded operators, fraction::operator+(fraction) and fraction::operator+(int), satisfying the first two requirements. However, neither overloaded operator can satisfy the third requirement. It isn't necessary to deal with the case of two integer operands - the "normal" addition operation works for fundamental data types.
Requirement 1 | Requirement 2 | Requirement 3 | |
---|---|---|---|
(a) | (b) | (c) |
fraction operator+(fraction f);
, created in the previous section.fraction fraction::operator+(int i);
, created in the previous section.Summarizing our progress to this point:
this
object bound to them during the call, match the third required calling pattern but can't access an object's private
members.friend
functions solve the problem:
friend
functions are not members of the befriending class,private
features.Non-Member (friend) Function | Partial fraction class |
---|---|
class fraction { private: int numerator; int denominator; public: fraction operator+(fraction f); // (1) fraction operator+(int i); // (2) friend fraction operator+(int i, fraction f2); // (3) }; |
|
(a) | (b) |
friend
allows it to access an object's private
members.
friend
functions, like overloaded operators, are controversial and disliked by some. Nevertheless, they provide an elegant solution when rigidly enforcing encapsulation results in inelegant code or fails to solve a necessary problem.
Although the three overloaded operators correctly process all possible addition operand patterns, they seem unnecessarily cumbersome and verbose. Fortunately, given one prerequisite, we can collapse the three overloaded operators into a single function. That prerequisite is a conversion constructor that converts an integer to a fraction object. Numerically, any integer, i, is equivalent to the fraction i/1, a conversion the original fraction constructor performs.
class fraction { private: int numerator; int denominator; public: fraction(int n = 0, int d = 1) : numerator(n), denominator(d) {} friend fraction operator+(fraction f1, fraction f2); };
(a) | (b) |
friend
function, and both operands are fractions. Nevertheless, it correctly processes all required operand patterns.