| |
| Main Menu for the Essentials of C++ |
| Next Section: Strings |
One can think of C++ operators as symbols (the technical term
is tokens) that trigger some computation. However, exactly
what computation is performed is not fixed. It depends on the
operands. For example, the addition of two integers requires a
different set of machine level instructions than the addition
of two doubles. One can therefore talk about the overloading of
operators.
Most computer languages do some overloading of operators as part of the language itself. It is possible, however, in C++ for programmers
themselves to re-define the meaning of C++ operators as long as
at least one of the operands is an instance of a class. Such overloading
allows one to, for example, add two dates using the '+' operator
or compare two weights (in pounds and ounces) using the relational
operators. As with functions, C++ determines which of the computations
associated with an operator to use by looking at the number and
types of the operands. (Operands are to an operator what parameters
are to a function.)
All operators with the exception of:
| . | the dot (or member selection) operator |
| :: | the scope operator |
| .* and ?: | not discussed in this text |
can be overloaded. However, different operators have different
restrictions and you should consult your C++ manuals for details
A. Declaring an Overloaded Operator
The general form to declare an operator overload is:
The word 'operator' followed by the operator symbol forms what
is called the operator function name. Thus, we refer to
overloaded operators as function operators or operator
functions.
For example, if we assume the existence of a class called 'Date', we could declare the overloaded operator function '+' that adds two instances of 'Date'and returns a Date as:
The number of arguments (operands) found in an overload declaration
depends on whether the operator function is declared as a friend
or member function of the class in question. (It must be one of
the two in order to have access to the members of the class.)
As declared here, the operator function '+' has two explicit operands,
'd1' and 'd2', and it has access to the internals of both of them
because it is a friend of 'Date'.
Since member functions have one implicit argument (a pointer to the instance being "sent the message" - representing by the keyword 'this'), member operator functions need one less explicitly declared operand. Thus the declaration for +=, meaning to add some number of days to a date might be:
We could also rewrite the declaration for '+' as:
In both these cases we only need one declared operand because
the other operand is implicit.
When adding two dates using the friend form of the overloaded '+' operator, the order of the operands is of little importance. Once could, for example, declare three dates as follows:
However, if we want to use the overloaded '+' operator to add some number
of days to a date, we need to be more careful. By using the declaration:
we are saying that '+' is a member operator function and that
the integer must be to the right of the '+' symbol since the operand
to the left is passed implicitly as a pointer to an instance of
'Date'. When dealing with member operator functions, the left
most operand must be an instance of a class. It would be more
versatile to rewrite this as two forms:
Now one can use this operator with an integer as the left or right
operand.
It is important that you carefully analyze the use of any overloaded
operators before you begin writing the declaration(s). Some operators:
must be declared as class members. In other cases, the decision belongs to the programmer. Clearly, if it makes sense for the operator to be commutative (so the operands can change order), the operator function should be made a friend. On the other hand, if the operator is always called with the left most operator being a class instance - as in '+=' in the dates example above - the operator function should be declared as a member of the class.
In certain circumstances, the traditional use of the operator
determines how it should be declared. For instance, we always
write:
To accomplish this (to overload the << operator to accept
dates as a data type) we must overload the << operator as
a friend since the left operand is not an instance of the 'Date'
class.
Finally, some experts argue that operator functions that have
no side effects should be written as friend functions since they
have no effect on the data members anyway.
B. Defining an Overloaded Operator
The code itself for an overloaded operator depends on what the
programmer wants to happen. There are no special rules. If the
overloaded operator is to be a member function, the scope operator,
::, must be included with the class name. It is also likely that
the keyword 'this' will be widely used. As an example, consider
the definition:
Since this operator returns the data passed in as an implicit
parameter after it has been modified , we return *this. Note that
*this is the result of dereferencing a pointer to a date. In many
cases the return type is declared as 'Date&' to return a reference
to the date and avoid a copy operation.
| |
Main Menu of Essentials of C++ | Next Section |