Tuesday, January 18, 2011

Overloading operators using member functions

In the lesson on overloading the arithmetic operators, you learned that when the operator does not modify it’s operands, it’s best to implement the overloaded operator as a friend function of the class. For operators that do modify their operands, we typically overload the operator using a member function of the class.
Overloading operators using a member function is very similar to overloading operators using a friend function. When overloading an operator using a member function:
  • The leftmost operand of the overloaded operator must be an object of the class type.
  • The leftmost operand becomes the implicit *this parameter. All other operands become function parameters.
Most operators can actually be overloaded either way, however there are a few exception cases:
  • If the leftmost operand is not a member of the class type, such as when overloading operator+(int, YourClass), or operator<<(ostream&, YourClass), the operator must be overloaded as a friend.
  • The assignment (=), subscript ([]), call (()), and member selection (->) operators must be overloaded as member functions.
Overloading the unary negative (-) operator
The negative operator is a unary operator that can be implemented using either method. Before we show you how to overload the operator using a member function, here’s a reminder of how we overloaded it using a friend function:
01class Cents
02{
03private:
04    int m_nCents;
05 
06public:
07    Cents(int nCents) { m_nCents = nCents; }
08 
09    // Overload -cCents
10    friend Cents operator-(const Cents &cCents);
11};
12 
13// note: this function is not a member function!
14Cents operator-(const Cents &cCents)
15{
16    return Cents(-cCents.m_nCents);
17}
Now let’s overload the same operator using a member function instead:
01class Cents
02{
03private:
04    int m_nCents;
05 
06public:
07    Cents(int nCents) { m_nCents = nCents; }
08 
09    // Overload -cCents
10    Cents operator-();
11};
12 
13// note: this function is a member function!
14Cents Cents::operator-()
15{
16    return Cents(-m_nCents);
17}
You’ll note that this method is pretty similar. However, the member function version of operator- doesn’t take any parameters! Where did the parameter go? In the lesson on the hidden this pointer, you learned that a member function has an implicit *this pointer which always points to the class object the member function is working on. The parameter we had to list explicitly in the friend function version (which doesn’t have a *this pointer) becomes the implicit *this parameter in the member function version.
Remember that when C++ sees the function prototype Cents Cents::operator-();, the compiler internally converts this to Cents operator-(const Cents *this), which you will note is almost identical to our friend version Cents operator-(const Cents &cCents)!
Overloading the binary addition (+) operator
Let’s take a look at an example of a binary operator overloaded both ways. First, overloading operator+ using the friend function:
01class Cents
02{
03private:
04    int m_nCents;
05 
06public:
07    Cents(int nCents) { m_nCents = nCents; }
08 
09    // Overload cCents + int
10    friend Cents operator+(Cents &cCents, int nCents);
11 
12    int GetCents() { return m_nCents; }
13};
14 
15// note: this function is not a member function!
16Cents operator+(Cents &cCents, int nCents)
17{
18    return Cents(cCents.m_nCents + nCents);
19}
Now, the same operator overloaded using the member function method:
01class Cents
02{
03private:
04    int m_nCents;
05 
06public:
07    Cents(int nCents) { m_nCents = nCents; }
08 
09    // Overload cCents + int
10    Cents operator+(int nCents);
11 
12    int GetCents() { return m_nCents; }
13};
14 
15// note: this function is a member function!
16Cents Cents::operator+(int nCents)
17{
18    return Cents(m_nCents + nCents);
19}
Our two-parameter friend function becomes a one-parameter member function, because the leftmost parameter (cCents) becomes the implicit *this parameter in the member function version.
Most programmers find the friend function version easier to read than the member function version, because the parameters are listed explicitly. Furthermore, the friend function version can be used to overload some things the member function version can not. For example, friend operator+(int, cCents) can not be converted into a member function because the leftmost parameter is not a class object.
However, when dealing with operands that modify the class itself (eg. operators =, +=, -=, ++, –, etc…) the member function method is typically used because C++ programmers are used to writing member functions (such as access functions) to modify private member variables. Writing friend functions that modify private member variables of a class is generally not considered good coding style, as it violates encapsulation.
Furthermore, as mentioned, some specific operators must be implemented as member functions. We’ll be covering most of these in upcoming lessons.

No comments: