| CS 202 Fall 2013 > Notes for Tuesday, October 1, 2013 |
CS 202 Fall 2013
Notes for Tuesday, October 1, 2013
Operator Overloading [14.5]
A Few Things Previously Covered
Overloading
Overloading a function means making two functions with the same name. In C++ we can do this as long as the functions have different parameter types.
[C++]
void foo(int a) { ... } double foo(int a, int b) // Okay { ... } int foo(double x) // Okay { ... } int foo(int c) // BAD!!!! { ... } // Same parameter types as 1st func
Parameter Passing
There are three ways to pass parameters in C++.
[C++]
X f(T by_value, T & by_reference, const T & by_reference_to_const);
We generally:
- Pass most simple types (like
int) by value. - Pass most objects by reference-to-const.
- Pass things we want to alter by reference.
Return Values
We can also return by reference. But be careful! Do not return a reference to something that is going away (like most local variables).
[C++]
int & byref1() { int x = 3; return x; // BAD!!! }
Some things are not going away, like reference parameters.
[C++]
int & byref2(int & x) { return x; // Okay }
DRY
Remember the DRY principle: Don't Repeat Yourself.
We saw examples of this when we called a set-function (“mutator”) from a constructor. We already wrote the code to set the value. we used this code—without repeating it—in the constructor.
About Operators
Consider the expression “x * y”.
The “*” is an operator.
x and y are its operands.
An operator has precedence, associativity, and arity.
Precedence tells where the parentheses go
when there are different kinds of operators.
For example,
“a + b * c”
is the same as
“a + (b * c)”,
because * has higher precendence than +.
Associativiy tells where the parentheses go
when the same kind of operator is used more than once.
For example,
“a / b / c”
is the same as
“(a / b) / c”,
because the / operator is left-associative.
But
“a = b = c”
is the same as
“a = (b = c)”,
because the = operator is right-associative.
Arity tells how many operands an operator has
- A unary operator has one operand.
In “
-x” we use the unary-operator. - A binary operator has two operands.
In “
a-b” we use the binary-operator. - A ternary operator has three operands.
C++ has just one ternary operator:
?:, as in “(a >= b) ? b : 0”.
The punchline: C++ allows us to write operator functions, which are called when an operator is encountered. We cannot create new operators, and we cannot change precedence, associativity, or arity. But we can overload existing operators for new types.
Writing Operator Functions
Operator functions can be member or global. I will look at writing them as global functions for now.
The name of an operator function is the word
“operator” followed by the operator
itself,
for example, “operator>=”.
Its parameters are the operands,
and its return value is the result.
Here is the binary + operator
for a class MyNum that I am writing.
[C++]
MyNum operator+(const MyNum & a, const MyNum & b) { ... }
I call this operator function using the “+”
operator.
[C++]
int a, b, c; a = b + c; // Does NOT call my function MyNum x, y, z; x = y + z; // Calls my function
Remember how we add global functions to a package: prototype in the header, definition in the source. A sample header file:
[C++]
// mynum.h ... class MyNum { ... }; MyNum operator+(const Mynum & a, const MyNum & b); ...
The corresponding source file:
[C++]
// mynum.cpp ... #include "mynum.h" ... MyNum operator+(const Mynum & a, const MyNum & b) { ... }
About return value methods:
- If modifying an existing value, then return by reference.
- If creating a new value, then return by value.
- (For future work) If giving access to an existing value, return by reference or by reference-to-const, depending on whether the value is modifiable.
Putting all these ideas together,
here is a += operator.
[C++]
MyNum & operator+=(MyNum & a, const MyNum & b) { ... return a; }
When we do “a += b;”,
we are modifying a, so we pass it by reference.
We are not modifying the object b,
so we pass it by reference-to-const.
Since we modify an existing value, we return by reference.
We generally consider += to be more fundamental
than +.
The first operator contains the code to do
addition.
We can use the first operator to write the second.
[C++]
MyNum operator+(const Num & a, const MyNum & b) { MyNum copy_a(a); copy_a += b; return copy_a; }
The above is correct for just about any new kind of addition.
A more fundamental operator may need to access private
class data.
So it may need to be declared a friend.
[C++]
class MyNum { ... friend MyNum & operator+=(MyNum & a, const MyNum & b); ... }; MyNum & operator+=(MyNum & a, const MyNum & b);
For today’s lab work, see the 10/1 Challenge.