3 Overloading
3 Overloading
Contents
Constructors and overloading....................................................................................................................... 1
Multiple Constructors ............................................................................................................................... 1
Function Overloading ................................................................................................................................ 5
Type Coercions .......................................................................................................................................... 7
Operator Overloading ............................................................................................................................... 9
Non-Member Operators ..................................................................................................................... 10
Multiple Constructors
A class can have more than one constructor, where each constructor is distinguished by its number of
parameters or type of parameters. Typically, the constructor with no parameter is called the default
constructor.
Example: We consider a class that we call Multiset. A Multiset is a collection of sorted items, where
duplicate items are allowed. For simplicity, we consider integer type items and they are sorted in
ascending order.
ADT: Multiset
Values:
MAX_SIZE
Items[MAX_SIZE]
Length
Operations:
Constructors: There are three constructors. The first constructor (default constructor) simply
initializes the number of elements to zero. The second constructor takes two integer parameters (say x
and n). It stores x in the Multiset n times. The third constructor takes an integer array and the number
of elements in the array. It initializes the Multiset to the array.
Page 1 of 10
IsFull: Check if a Multiset instance is full.
Delete: Delete an item from a Multiset instance. If multiple occurrences of the same item have
been inserted into the Multiset instance, then only one occurrence is removed. If none are present, then
do nothing.
class Multiset
{
public: const unsigned int MAX_SIZE = 500;
private: int items[MAX_SIZE];
int length;
public:
Multiset();
Multiset(int x, int n);
Multiset(int A[], int n);
bool isEmpty();
bool isFull();
bool isMember(int x);
int getLength();
void insert(int x);
void delete(int x);
void print();
}
multiset.cpp
#include <iostream>
using namespace std;
#include "multiset.h"
Multiset::Multiset()
{
length = 0;
}
Page 2 of 10
Multiset::Multiset(int x, int n)
{
length = 0;
for (int i = 0; i < n; i++)
insert(x);
}
bool Multiset::isEmpty()
{
return ( length == 0 );
}
bool Multiset::isFull()
{
return ( length == MAX_SIZE ) ;
}
bool Multiset::isMember(int x)
{
for (int i = 0; i < length; i++)
if (items[i] == x )
return true;
return false;
}
int Multiset::getLength()
{
return length;
}
void Multiset::insert(int x)
{
if ( length<MAX_ITEM )
{
for (int i = length – 1; i >= 0 && x < items[i]; i--)
items[i+1] = items[i];
items[i+1]=x;
length++;
}
}
Page 3 of 10
void Multiset::delete(int x)
{
for (int i = 0 ; i < length ; i++)
{
if ( items[i] == x )
{
for (int j = i + 1; j < length ; j++)
items[j-1] = items[j];
length--;
return;
}
}
}
void Multiset::print()
{
for(int i = 0; i < length; i++)
cout<<items[i]<<endl;
}
Example: Write a member function of Multiset that we call Merge. Merge combines the items of two
Multiset instances into one instance and returns the resultant instance.
Example: Write a member function of Multiset that we call MergeArrays. MergeArrays combines the
items of two arrays into an instance of Multiset, and returns the resultant instance.
Multiset Multiset::MergeArrays( int A[], int n1, int B[], int n2)
{
return Multiset(A[], n1).Merge( Multiset(B[],n2) );
}
Page 4 of 10
Example: Write a member function of Multiset that we call IsEqual. IsEqual returns true if two
instances of Multiset are identical. Otherwise, it returns False.
Example: Make a Multiset array of size 5, and then initialize the instances with the following data
constructs:
(i) A[] = {2,3,6,7,9}.
(ii) B[]={6,4,2,9,10,7}.
(iii) Combination of arrays A and B.
(iv) C[]={};
(v) 10 zeroes.
Answer:
Multiset x[5];
(i) x[0].Multiset(A[], 5).
(ii) x[1].Multiset(B[],6);
(iii) x[2].MergeArrays(A[], 5, B[], 6);
(iv) x[3].Multiset(C[], 0);
(v) x[4].Multiset(0, 10);
Exercise: Implement a constructor for Multiset that, given integral arguments i, d and n, initializes a
new Multiset instance to hold the following sequence:
i, i + d, i + 2 * d, i + 3 * d, ..., i + (n-1) * d
Function Overloading
Several functions (inside a class or outside a class) can share a same name but they can be distinguished
by the number of parameters or the type of the parameters. This idea is called function overloading.
The act of selecting the correct function out of many functions with a same name, is called function
disambiguation.
Page 5 of 10
Example: Write a function (called myMax) that takes number parameters and returns the maximum
number. Note that the numbers can be integer or float. The function myMax can take two or three
parameters.
int myMax(int a, int b)
{
if (a > b)
return a;
else
return b;
}
float myMax(float a, float b)
{
if (a > b)
return a;
else
return b;
}
int myMax(int a, int b, int c)
{
return myMax(a, myMax(b, c));
}
float myMax(float a, float b, float c)
{
return myMax(a, myMax(b, c));
}
In this case, the myMax function is called an overloaded function.
Example: Perform the overloading of the insert function of the Multiset class so that the insert function
can insert an array in a Multiset instance.
void insert(const int A[], unsigned int n)
{
for (int i = 0; i < length; i++)
insert(ietms[i]);
}
Example: Consider two classes, Counter and Time. Write a function (called print) of the Counter class
that prints the field count. Write a function (called print) of the Time class, which prints the field
seconds.
void Counter::print()
{
cout<<count;
}
void Time::print()
{
cout<<seconds;
}
Note that the name and parameter of both functions are same but they are different functions as they
are in two different classes and their scopes are different.
Page 6 of 10
Type Coercions
When the value of a type is changed to the corresponding value of a different type, we call it type
coercion. Type coercion typically occurs before applying operators, during passing value to a function,
or during returning value from a function.
If we call the function for two integer values, such as add(5,9), it the call valid?
The call is valid as a value of an integer type can be changed to the corresponding value of a double
type. We call it a safe coercion. Safe coercions are typically executed without an error or a warning.
A safe coercion occurs if we maintain the following order, i.e., a short int can be converted to a double.
Char -> short int -> int -> long int -> float -> double
If we call the function for two double values, such as add(5.7,9.4), is the call valid?
The call is invalid as a value of an double type cannot be changed to the corresponding value of an
integer type. We call it an unsafe coercion. Unsafe coercions typically generate an error.
When a function call occurs, the compiler typically maintain the following rules:
-Compiler finds a function so that a coercion is not needed, and that function is executed.
-Compiler finds a matching function with a safe coercion, and that function is executed.
-If more than one matching with a safe coercion is found or more than one matching with an
unsafe coercion is found, we call that it is ambiguous, and an error is generated.
Page 7 of 10
Example: Given the following pairs of prototypes, and assuming that only safe coercions are performed,
identify which function the compiler would match with the function call (your answer should be A, B, C
(neither is a safe match), or D (ambiguous: both are safe matches and neither is preferred)):
1. void myMax(float f1, float f2); // A
void myMax(int i1, int i2); // B
myMax(7, 9);
2. void zipIt(float f1); // A
void zipIt(string s1); // B
String s = "Trouble";
zipIt(s);
3. void zoom(float f1); // A
void zoom(string s1); // B
int x = 14;
zoom(x);
4. void whoosh(char c1); // A
void whoosh(string s1); // B
double pi = 3.14159;
whoosh(pi);
5. void crunch(string s1, string s2); // A
void crunch(string s1); // B
double e = 2.71828;
crunch(e);
6. void mixed(int i1, double d1); // A
void mixed(double d1, int i1); // B
int k3 = 3, k4 = 4;
mixed(k3, k4);
7. void mixed(int i1, double d1); // A
void mixed(double d1, int i1); // B
double r5 = 55.5, r6 = 66.6;
mixed(r5, r6);
Answers:
1. B; exact match
2. B; exact match
4. C; unsafe: some compilers will coerce double to char (and some of these give a warning
about loss of precision)
5. C: syntax error from compiler; compilers do not perform coercions to strings because string is
a class
6. D: syntax error from compiler (call is ambiguous between two safe coercions)
7. C: syntax error from compiler (call is ambiguous between two unsafe coercions)
Page 8 of 10
Operator Overloading
Operator overloading refers to giving more than one meaning to the same operator. It is commonly
done when creating new data types (e.g., using classes). An overloaded operator can be a member
function of a class with the syntax operatorX, where the X is an operator, e.g., +, ==, *, etc.
(a) Write an operator == that returns true if two instances of Time are same; otherwise it returns false.
bool Time::operator==(const Time& t) const
{
if (seconds == t.seconds) return true;
return false;
}
(c) Write an operator + that adds two instances of Time and saves the result into another instance.
Time Time::operator+ (const Time& t)
{
Time newTime;
newTime.seconds = seconds + t.seconds;
return newTime;
}
The leftmost operand of any operator is the class instance invoking the operator. So in t2 = t1, the
instance is t2 and the remaining operand t1 is treated as a parameter.
Page 9 of 10
Non-Member Operators
It is possible to specify most overloaded operators as non-member functions. When specifying an
overloaded operator as a non-member function, there is no invoking instance, so the operator will need
another parameter.
(a) Write a non-member operator == that returns true if two instances of Time are same; otherwise it
returns false.
bool Time::operator==(const Time& t1, const Time& t2)
{
if (t1.seconds == t2.seconds) return true;
return false;
}
(b) Write a non-member operator = that assigns an instance of Time to another instance.
void Time::operator=(Time& t1, const Time& t2)
{
if (t1 != t2)
t1.seconds = t2.seconds;
}
(c) Write a non-member operator + that adds two instances of Time and saves the result into another
instance.
Time Time::operator+ (const Time& t1, const Time& t2)
{
Time newTime;
newTime.seconds = t1.seconds + t2.seconds;
return newTime;
}
Page 10 of 10