0% found this document useful (0 votes)
7 views10 pages

3 Overloading

Uploaded by

herig81818
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views10 pages

3 Overloading

Uploaded by

herig81818
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

These notes were adapted from ones originally developed by Howard Hamilton and Philip Fong,

Department of Computer Science, University of Regina.

Contents
Constructors and overloading....................................................................................................................... 1
Multiple Constructors ............................................................................................................................... 1
Function Overloading ................................................................................................................................ 5
Type Coercions .......................................................................................................................................... 7
Operator Overloading ............................................................................................................................... 9
Non-Member Operators ..................................................................................................................... 10

Constructors and overloading


In this lecture we examine the concept of overloading, which refers to giving additional meanings to
function names and operators. We begin by reviewing the fact that one can define multiple constructors
for a class.

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.

The description of the class is as follows.

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.

IsEmpty: Check if a Multiset instance is empty.

Page 1 of 10
IsFull: Check if a Multiset instance is full.

IsMember: Test if an item is in a Multiset instance.

GetLength: Get the number of items in a Multiset instance

Insert: Insert an item into a Multiset instance.

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.

Print: Print the members of a Multiset instance in ascending order.

Declare and implement the class in C++.

Declaration (or interface) of Multiset class:


multiset.h

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();
}

Definition (or implementation) of Multiset class:

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);
}

Multiset::Multiset(int A[], int n)


{
length = 0;
for (int i = 0; i < n; i++)
insert(A[i]);
}

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.

Multiset Multiset::Merge( Multiset& x)


{
Multiset y;

for (int i = 0; i < length; i++)


y.insert( items[i] );

for (int i = 0; i < x.length; i++)


y.insert( x.items[i] );
return y;
}

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.

bool Multiset::IsEqual( Multiset& x)


{
If ( length != x.length)
return false;

for (int i = 0; i < length; i++)


if ( items[i] != x.items[i] )
return false;
return true;
}

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.

Example (Safe coercion): Consider the following function.


void add(double a, double b)
{
cout<< (a+b);
}

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

Example (Unsafe coercion): Consider the following function.


void add(int a, int b)
{
cout<< (a+b);
}

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 no matching with a safe coercion is found an error is generated.

-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

3. A; safe coercion of int to float

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.

Example: Recall the Time class.

(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;
}

(b) Write an operator = that assigns an instance of Time to another instance.


void Time::operator=(const Time& t)
{
if (this != &t)
seconds = t.seconds;
}

(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.

Example: Recall the Time class.

(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

You might also like