FAQ 19.11 What qualities suggest a friend function rather than a member function?

The three P's of friendship: position, promotion, or perception.

Position: Use a friend function when the object being operated on can't appear as the leftmost argument. For example, the syntax to print an object n is usually cout << n, where cout can be replaced by any ostream. Notice that n is not the leftmost argument and therefore operator<< cannot be a member of n's class. If operator<< needs access to n's internal state, it must be a friend of n's class.

 #include <iostream> using namespace std; class Fraction { public:   Fraction(int num=0, int denom=1) throw();   friend ostream& operator<< (ostream& o, const Fraction& n)                               throw(); protected:   int num_, denom_; }; Fraction::Fraction(int num, int denom) throw() : num_   (num) , denom_ (denom) { } ostream& operator<< (ostream& o, const Fraction& n) throw() { return o << n.num_ << '/' << n.denom_; } int main() {   Fraction n = Fraction(3,8);    // "3/8"   cout << "n is " << n << '\n'; } 

Promotion: Use a friend function to allow promotion of the leftmost argument. For example, the Fraction class might want to support 5*n, where n is a Fraction object. This may require promoting the leftmost argument from an int to a Fraction, where this is implemented by passing a single int parameter to Fraction's constructor Fraction(5). The operator* needs to be a friend because C++ never automatically promotes the this object in a member function invocation.

 #include <iostream> using namespace std; class Fraction { public:   Fraction(int num=0, int denom=1) throw();   friend Fraction operator* (const Fraction& a,                              const  Fraction& b) throw(); protected:   int num_, denom_; }; Fraction::Fraction(int num, int denom) throw() : num_(num), denom_(denom) { } Fraction operator* (const Fraction& a, const Fraction& b) throw() { return Fraction(a.num_*b.num_, a.denom_*b.denom_); } int main() {   Fraction x = Fraction(3,8);        // "3/8"   Fraction y = 5*x; } 

Perception: Use a friend function when it leads to a user syntax that is more intuitive. For example, two possible syntaxes for computing the square of a fraction n are n.square() and square(n) (for example, 1/2 squared is 1/4). If the operation is constructive (if n is unchanged), square(n) may be preferred because n.square() might be incorrectly perceived as squaring n itself.

 #include <iostream> using namespace std; class Fraction { public:   Fraction(int num=0, int denom=1) throw();   friend Fraction square(const Fraction& n) throw(); protected:   int num_, denom_; }; Fraction::Fraction(int num, int denom) throw() : num_(num), denom_(denom) { } Fraction square(const Fraction& n) throw() { return Fraction(n.num_*n.num_, n.denom_*n.denom_); } int main() {   Fraction x = Fraction(3,8);        // "3/8"   Fraction y = square(x); } 

Of the three P's for choosing between friend functions and member functions, perception is the most subjective. In many cases involving perception, a static member function such as Fraction::square(n) is better than a friend function.



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net