In this lab you will learn how to overload functions and operators. You will be able to recognize and write overloaded functions and you will be able to define your own operators. Specifically, the following topics will be covered:
Overloading is a component of polymorphism in C++. It lets a programmer use one function name for multiple functions. The compiler chooses what implementation to use based on the arguments provided in the call. Functions can be overloaded to handle different types of data and different numbers of parameters. You can also overload certain operators, including +, /, <<, and even [ ]. This can add power and ease of use to user defined data types.
Briefly, function overloading means two or more functions share the same name but their parameters are different. In this situation, the functions that share the same name are said to be overloaded and the process is called function overloading . The number and types of a function's parameters are called the function's signature. Together a function's name and its signature uniquely identify it.
This refers to the situation where the overloaded functions have the same number of parameters, but the types are different.
// File name: /pub/class/170/ftp/cpp/Inheritance/OverloadSingle.cpp
// Purpose: Demonstrate single parameter overloading
//Overloaded functions with same number of parameters, but
//different types.
void timesTwo(int &num);
void timesTwo(double &num);
int main(void)
{
int A = 1;
double B = 1.1;
timesTwo(A); // Changes A to 2
timesTwo(B); // Changes B to 2.2
}
// handle int type
void timesTwo(int &num)
{
num = num * 2;
}
// handle double type
void timesTwo(double &num)
{
num = num * 2.0;
}
In the above example, there are two versions of the timesTwo function; one deals with integers and the other deals with double. When we call the function with different data types, the compiler is able to decide which version of the timesTwo() function to call by comparing the type of the argument in the function call with the type of the parameter of the available function versions. If the call argument is of type int then the function version with an int parameter is called. Similarly if the call argument is of type double then the function version with a double parameter is called.
This refers to the situation where the types of parameters of the overloaded functions may or may not be the same and the number of parameters is different.
Let's look at the following example:
// File name: /pub/class/170/ftp/cpp/Inheritance/OverloadMultiple.cpp
// Purpose: Demonstrate multiple parameter overloading
#include <iostream>
using namespace std;
void add(int i, int j);
void add(int i, double j);
void add(int i, int j, int k);
int main(void)
{
int A = 1, B = 2, C = 3;
double D = 1.1;
add(A, B); // 1 + 2 => add prints 3
add(A, D); // 1 + 1.1 => add prints 2.1
add(A, B, C); // 1 + 2 + 3 => add prints 6
}
void add(int i, int j)
{
cout << "Result: " << i + j << endl;
}
void add(int i, double j)
{
cout << "Result: " << i + j << endl;
}
void add(int i, int j, int k)
{
cout << "Result: " << i + j + k << endl;
}
The above program gives the following results:
mercury[18]% CC -o OverloadMultiple OverloadMultiple.cpp mercury[19]% OverloadMultiple Result: 3 Result: 2.1 Result: 6 mercury[20]%
//In matrix.h
class Matrix
{
private:
int doubleArray[MAXROWS][MAXCOLS];
int rows;
int cols;
public:
.
.
.
//add an array to current data in "doubleArray"
void addMatrix(int [][MAXCOLS]);
//add two arrays together and store the results in "doubleArray"
void addMatrix(int [][MAXCOLS], int [][MAXCOLS]);
.
.
.
//In matrix.cpp
void Matrix::addMatrix(int array1[][MAXCOLS])
{
...
}
void Matrix::addMatrix(int array1[][MAXCOLS], int array2[][MAXCOLS])
{
...
}
You can overload operators in the same way that you overload functions. There are only three things you need to know:
The following table (taken from C++ Primer, Lippman and Lajoie) is the predefined set of C++ operators that may be overloaded:
Table of Overloadable Operators
| + | - | * | / | % | ^ | & | | | ~ |
| ! | , | = | < | > | <= | >= | ++ | -- |
| << | >> | == | != | && | || | += | -= | /= |
| %= | ^= | &= | |= | *= | <<= | >>= | [] | () |
| -> | ->* | new | new[] | delete | delete[] |
You cannot overload ::, .*, . or ?:.
NOTE: the point of operator overloading is to be intuitive. You do not want to assign a confusing operator name. For instance, you do not want to overload the "+" when the function actually performs subtraction.
Most operators you can overload are either binary or unary. Binary operators have a left-hand side and a right-hand side usually written LHS and RHS. For non-member functions each side is a parameter. The LHS is the first parameter, the RHS is the second.
return_type operatorbinary(type LHS, type RHS)Unary operators have only one parameter.
return_type operatorunary(type param)
Some operators can be both binary and unary. Which overloaded definition is used is determined by context and function signature. Suppose you wanted to overload subtraction and negation. These expressions:
matrix1 - matrix2 -matrix1are transformed into function calls like these by the compiler:
operator-(matrix1,matrix2)//subtraction operator-(matrix1) //negationThe following example shows how you would overload operators += and ++ on a matrix using the addMatrix member function:
//For Reference, this is the definiton of addMatrix in matrix.cpp
void Matrix::addMatrix(int otherArray[][MAXCOLS])
{
for (int i=0; i< rows; i++)
{
for(int j=0; j< cols; j++)
{
doubleArray[i][j] += otherArray[i][j];
}
}
}
// Code could be in main.cpp
#include <iostream>
#include "matrix.h"
using namespace std;
//operator +=
Matrix operator+=(Matrix &mat, int arr[MAXROWS][MAXCOLS]);
//Prefix operator ++
Matrix operator++(Matrix &mat);
int main()
{
int Num1[MAXROWS][MAXCOLS] =
{
{1,2,3},
{4,5,6}
};
Matrix matrix1;
cout << "matrix1 initialized:" << endl;
matrix1.printMatrix();
cout << "Num1 added to matrix1 with += " << endl;
matrix1 += Num1;
matrix1.printMatrix();
cout << "1 added to all elements of matrix1 with ++ " << endl;
++matrix1;
matrix1.printMatrix();
cout << "\n" << endl;
return 0;
}
Matrix operator+=(Matrix &mat, int arr[MAXROWS][MAXCOLS])
{
mat.addMatrix(arr);
return mat;
}
Matrix operator++(Matrix &mat)
{
//Build an array of 1's with correct dimensions
int arr[MAXROWS][MAXCOLS];
for(int i = 0; i < MAXROWS; i++)
for(int j = 0; j < MAXCOLS; j++)
arr[i][j] = 1;
//Add it to the matrix
mat.addMatrix(arr);
return mat;
}
Notice that non-member functions do not have access to private data. That's why operator++ uses addMatrix and an array initialized with 1's to do its work. Normally you would need to use observer and transformer member functions on an object. C++ has the keyword friend you can use as a workaround to this restriction, you may wish to look it up.
Also notice that operator++ is a prefix operator. To change it to a postfix operator add an unnamed second parameter of type int.
A class is a legal return type for a function. . Arrays are not a legal return type — that's one reason we built our matrix class.
When you overload an operator as a member function the LHS of binary operations and the only parameter of unary operations is implied. That parameter is assumed to be the calling object. If subtract and negate were defined as member operators of the matrix class then
matrix1 - matrix2 -matrix1would become
matrix1.operator-(matrix2) matrix1.operator-()Those are legal member function calls.
The changes you need to overload the non-member operators += and ++ above as member operators follow.
In matrix.h add these operator prototypesMatrix operator+=(int arr[MAXROWS][MAXCOLS]); Matrix operator++(/*No parameters*/);Now change the function definitions as follows
Matrix Matrix::operator+=(int arr[MAXROWS][MAXCOLS])
{
addMatrix(arr);
return *this; //We will talk about this in CS210
}
Matrix Matrix::operator++(/*No parameters*/)
{
//No need for array
//Add 1 to the all elements of the matrix
for(int i = 0; i < MAXROWS; i++)
for(int j = 0; j < MAXCOLS; j++)
doubleArray[i][j] += 1;
//No need for extra call
return *this; //We will talk about this in CS210
}
Notice that a member function has access to the private data members of parameters that belong to the same class.
Usually it is up to you to decide where to overload an operator. Sometimes you have no choice; you are required by some limitation to define an operator as a class member or as a non-member.
Some programmers prefer to define operators on object/non-object pairs as non-member functions. This way the definition that cannot be a member is defined similarly to the one that can like this:
#include <math.h>
//...
bool operator<(twoD b, int a)
{
if (sqrt(b.x*b.x+b.y*b.y) < a) return true;
return false;
}
bool operator<(int a, twoD b)
{
if (sqrt(b.x*b.x+b.y*b.y) > a) return true;
return false;
}
Complete the following worksheets.
Consider two functions with the same name. How do each of the following differ in signature? (Indicate "same" or "different" in the following tables.)
| Function Prototype | Function Signature | |
|---|---|---|
| # of param's | type of param's | |
add(int i, int j); |
||
add(int i, int j); |
||
add(int i, int j, int k); |
||
add(double i, double j, double k); |
||
Given m1 and m2 of type Matrix and a1 of type int [][] are the following operators unary or binary? Can they be member or non member functions or both? Indicate all that apply.
| Expression | arity | Class Membership |
||
|---|---|---|---|---|
| unary | binary | M | N-M | |
m1+m2 |
||||
m1=a1 |
||||
m1++ |
||||
a1*m1 |
||||
-m1 |
||||
For this part you will overload some member and non-member operators for our Matrix class.
cp /net/data/ftp/pub/class/170/ftp/cpp/Overload/exercise2.zip exercise2.zip unzip exercise2.zip
The password for this zip file is: linalg
Notice that a exercise2 directory is created for you
g++ -c main.cpp -o main.o main.cpp: In function `int main()': main.cpp:30: error: no match for 'operator-' in 'mat1 - Num2' main.cpp:36: error: no match for 'operator-' in 'Num1 - mat1' main.cpp:44: error: no match for 'operator-' in '-mat1' main.cpp:49: error: no match for 'operator+=' in 'mat1 += Num2' main.cpp:53: error: no match for 'operator+=' in 'mat1 += mat1' make: *** [main.o] Error 1
If you have a Makefile you can compile and debug in Emacs:
M-x compile then hit Enter twice. A new frame with your compiler output will appear.C-x o until you get to the compiler output frame. Then use the arrow keys to find the line you want to fix and hit Enter. You will be taken to the line you want.
Test member subtraction:
mat1:
1 2 3
4 5 6
mat2:
-5 -3 -1
1 3 5
Test non-member subtraction:
mat1:
1 2 3
4 5 6
mat2:
0 0 0
0 0 0
Test negation:
mat1:
1 2 3
4 5 6
mat2:
-1 -2 -3
-4 -5 -6
Test += with 2d array:
mat1:
7 7 7
7 7 7
Test += with Matrix:
mat1:
14 14 14
14 14 14
|
Thursday, 06-Oct-2011 12:13:32 CST |
| |
|
|