C++ allows almost all operators to be overloaded to apply to class objects. For example, the following code shows some operators (in red) being applied to objects of type Intlist:
IntList L1, L2, L3; L1 += 10; L3 = L1 + L2; cout << L1; if (L1[0] == 5) ... if (L1 == L2) ...
It is important to note that if you do not define these operators to apply to your class, you will get a compile-time error if you write code that does apply them to class objects; the compiler supplies a default version only for operator= (assignment).
Note also that when you overload operators, at least one operand must be a class object (or an enum). For example, you can redefine the plus operator applied to an IntList and an integer, or to two IntLists, but you cannot redefine plus applied to two integers. You also cannot redefine the arity of an operator; for example, you cannot define plus to have three operands.
Some operators are unary (have one operand), and some are binary (have two operands). The example given above includes only binary operators: +=, +, <<, [], and ==. Examples of unary operators are: unary minus, pre- and post-increment, and pre- and post-decrement.
Unary operators, and binary operators whose left operands are class objects, can be defined either as member functions of that class, or as free functions. Binary operators whose left operands are not class objects must be defined as free functions.
In the statement:
L1 += 10;the left operand of += is an IntList, and its right operand is an integer. Therefore, this version of += can be defined either as an IntList member function or as a free function. Here is how it might be defined as a member function:
class IntList { public: void operator+=( int n ); ... }; void IntList::operator+=( int n ) { AddToEnd( n ); }Note that it is up to the designer of the class to decide what it means to apply an operator to a class object. This definition of operator+= adds the right-hand operand (the integer value) to the end of the list represented by the left-hand operand (the IntList whose member function is called). It would also be reasonable to define operator+= to add the integer to the front of the list.
In the statement:
cout << L1;the left operand of << is an ostream, not an IntList. Therefore, operator<< cannot be defined as a member function of the Intlist class; it must be defined as a free function. For example:
ostream &operator<<( ostream &out, const IntList &L ) { L.Print(out); return out; }Note that operator<< should be defined to return an ostream (so that "chained" output, like: cout << L1 << endl will work). (It is returned by reference -- that's what the & means -- for efficiency.) Also note that operator<<'s first parameter must be an ostream passed by reference. Its second parameter, the IntList that is printed, does not have to be passed as a const-reference parameter; however it is more efficient to pass it by reference than by value (since that avoids a call to the copy constructor), and it should not be modified by operator<<, so it should be a const reference parameter.
Note also that this code assumes that the IntList class has a Print function. If that is not true, then operator<< must be declared to be a friend function of the IntList class, so that it has access to the private Items and numItems fields (which it needs in order to be able to print the contents of the list). In that case, the function would be declared like this:
class IntList { friend ostream &operator<<( ostream &out, const IntList &L ); public: ... };and defined like this:
ostream &operator<<( ostream &out, const IntList &L ) { out << "[ "; for (int k=0; k< L.numItems; k++) { out << L.Items[k] << ' '; } out << ']'; }
Define operator== first as an IntList member function and then as a free function (in both cases, the function should return true iff both of the operands of == contain the same sequence of integer values).
Solutions to Self-Study Questions
Here is operator== as an IntList member function:
bool IntList::operator==(const IntList &L) const { // check lengths of lists if (numItems != L.numItems) return false; // check contents of lists for (int k=0; k<numItems; k++) { if (Items[k] != L.Items[k]) return false; } return true; }Note that, since the function does not modify any of the IntList's fields, it is declared to be a const member function.
And here it is as a free function:
bool operator==(const IntList &L1, const IntList &L2) { // check lengths of lists if (L1.numItems != L2.numItems) return false; // check contents of lists for (int k=0; k<L1.numItems; k++) { if (L1.Items[k] != L2.Items[k]) return false; } return true; }