CS 218 - Object Oriented Programming with C++

Chapter 15 - Overloading and Templates

Objectives:

This chapter overloading: redefining something that is already defined. Objectives important to this chapter:

  1. Defining overloading
  2. The operator function
  3. Restrictions on overloading operators
  4. Overloading operators
  5. Friends
  6. Templates
Concepts:

This chapter begins by explaining that we could simplify the use of the clockType class from chapter 12 by extending the definitions of standard C++ operators. It would be convenient, for instance to be able to use the incrementation operator, the comparison operator, and the insertion operator on this class instead of using the functions that chapter 12 had you write to increment, compare, and output data from this class.

We could not use the standard operators because the only operators chapter 12 taught us to use (the only ones that would work on a class) were the assignment and member selection operators. This chapter explains how to write additional definitions for these operators. Doing so is called overloading the operators. Note: we are not redefining what the operators do. We are adding new abilities to those operators.

When we overload an operator, we are teaching it to do something new. The text explains that the division operator (/) is already overloaded, because it can do two kinds of division: integer division and floating-point division. We learned in the last chapter that the incrementation operator is overloaded, because it produces one kind of result if its operand is an integer, and another kind of result if its operand is a pointer.

It follows, then, that to overload an operator, we must teach it to do something different when it has different kinds of operands. To do this we write a function whose name will be the word operator, immediately followed by the operator we are overloading. Example:
returnType operator+(parameters) // this would be part of an overload function for the + operator. The words in italics would be replaced with an actual return type and a formal parameter list.

The text explains that you must follow several rules (restrictions) when overloading an operator:

  1. You can't change the precedence of the operator.
  2. You can't change the associativity (left to right, or right to left) of the operator
  3. Default parameters can't be used with an overloaded operator. (It will require parameters.)
  4. You can't change the number of parameters the operator takes,
  5. You can overload an existing operator, but you can't create a new operator.
  6. You are not allowed to overload five operators:  .   .*   ::   ?:   sizeof
  7. You are not allowed to change already defined behaviors of the operator with built-in types.
  8. You are allowed to overload behaviors for user-defined types or combinations of user-defined types and built-in types.

A question may need to be answered: why do we need to overload an operator? We need to do so if we want to use that operator with a class or a struct that we create.

The text briefly discusses this. Every object of any class has a hidden pointer to itself. That pointer is called this. For the purposes of this class, be aware that every object of every class has such a pointer, and it points to the object itself.

The text returns to the concept of friends by discussing friend functions. This is a little odd. (Right. As though the other concepts in the second half of the book aren't.) We declare a friend function in a class, as though it was a member of the class. The text states, however, that a friend function is not a member of that class. Example:
class BingType
{
void chandler(int); // This is a prototype for a member function
void monica(double); // This is a prototype for another member function
friend void joey(char); // This is a prototype for a friend. It is not a member of the class BingType, but it will have access to all the members of BingType: public, protected, and private.
};

We use the keyword friend in the prototype for the friend function to accomplish two things: the friend is granted access to all members of the class, and it is tagged as not being a member of the class itself.

So, why does this chapter care about friends? It is important because it relates to overloading operators. We have to write a function to overload an operator (teach it what to do with a new data type). If we are overloading an operator for a class, the function that we write can be a member of the class, or it can be a friend of that class. Making it a friend gives us the option of making it more modular and reusable for other classes.

There are more restrictions on friend vs. member:

  • If a function overloads any of the operators ( ), [ ], ->, or = for a class, it must be declared as a member of the class (not as a friend).
  • If the operator that a function is overloading takes a class object as its right-hand operand, and a a non-class object as its left-hand operand (anything other than an object of that class), the function must be a friend function of that class, not a member function.
  • Conversely, if the operator takes a class object as its left-hand operand, the function that overloads the operator must be a member function of the class.
  • Arithmetic and relational operators can be overloaded by friend or member functions.

More concise information on overloading can be found at C++ FAQ Lite.

A good discussion of templates can also be found at C++ FAQ Lite.