KEMBAR78
C++ - More About Classes and Objects | PDF | Parameter (Computer Programming) | Software Development
0% found this document useful (0 votes)
39 views140 pages

C++ - More About Classes and Objects

Uploaded by

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

C++ - More About Classes and Objects

Uploaded by

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

More about Classes and

Objects
Concept

By default, the compiler


provides each member
function of a class with an The implicit parameter is
implicit parameter that points called this
to the object through which
the member function is called
The this Pointer

Consider this class… and this member function

class Example
{ int Example::getValue()
int x;
{
public:
Example(int a){ x = a;} return x;
void setValue(int); }
int getValue();
};
class Example
{
int x;
The this int Example::getValue()
{
public: Pointer return x;
Example(int a){ x = a;}
}
void setValue(int);
int getValue();
};

int main()
{
10 20
Example ob1(10), ob2(20);
cout << ob1.getValue() << " " << ob2.getValue();
return 0;
}
Learned earlier…

Each instance of a These instance


Different objects of a
class has its own copy members can have
class are called
of the data members different values in
instances of that class
listed in the class. different objects.
int main()
{ Learned
Example ob1(10), ob2(20);
cout << ob1.getValue() << " " << ob2.getValue();
earlier…
return 0;
}

The instance member X in the ob1 object has a value of 10


while x in ob2 has a value of 20
ob1 ob2

X 10 X 20
int Example::getValue() Consider this
{ member
return x; function again
}

Returns the X member of some object of the Example


class…how does it know which object to use?
ob1 ob2

X 10 X 20
int Example::getValue()
{ Answer!
return x;
}

Compiler provides each member function of every class with an


implicit parameter that is a pointer to an object of the class.

ob1 ob2

X 10 X 20
int Example::getValue()
{ ob1.getValue()
return x;
}

The implicit parameter passed to getValue is the


address of ob1
ob1 ob2

X 10 X 20
int Example::setValue(int num)
{ ob2.setValue(5);
x = num;
}

The explicit and implicit parameters passed to


setValue are the value 5 AND &ob2
ob1 ob2

X 10 X 20
int Example::setValue(int num)
{ ob2.setValue(5);
x = num;
}

The implicit pointer passed by the compiler to a


member function can be accessed by code
inside that function by using the reserved
keyword this 🡪 *this
void Example::setValue(int a)
Exampl {
e class }
x = a;

void Example::printAddressAndValue()
{
cout << "The object at address " << this << " has "
<< "value " << (*this).x << endl;
}
class Example
{
int x;
public:
Example(int a){ x = a;}
void setValue(int);
void printAddressAndValue();
};
Example ob1(10), ob2(20);

// Print the addresses of the two objects


cout << "Addresses of objects are " << &ob1
<< " and " << &ob2 << endl;
// Print the addresses and values from within
// the member function
ob1.printAddressAndValue();
ob2.printAddressAndValue();

Addresses of objects are 0x241ff5c and 0x241ff58


The object at address 0x241ff5c has value 10
The object at address 0x241ff58 has value 20
Example of a common use of the this pointer
void Example::setValue(int a)
{ Notice the use of
function parameter
x = a;
“a” instead of “x”.
}

If we used “x” as the parameter, then it would “hide”


the class member “x”, making it inaccessible inside the
Function 🡪 x = x would confuse things…
Example of a common use of the this pointer
void Example::setValue(int x)
{ By using this, we
can now use a
this -> x = x;
parameter of “x”
}

Note: this -> x is equivalent to (*this).x


Concept

A constant member
function is one that does
NOT modify the object
through which it is called
Constant function parameter Example

void fun(const string &str);

• Takes a reference to a string object but will


NOT be able to modify the object
• A similar mechanism can be used to protect
a function from modifying the current object
Constant Member Function

When placed after the parameter list in


the definition of a member function, the
const key word informs the compiler that
the function should not be allowed to
modify its object.
int ConstExample::getValue() const
class ConstExample
{
{ return x;
int x; }
public:
ConstExample(int a){ x = a;}
void setValue(int);
int getValue() const;
};
The function getValue can NOT modify the object now
If it had code such as x = 10; then it would compile
class ConstExample int ConstExample::getValue() const
{ {
int x; return x;
}
public:
ConstExample(int a){ x = a;}
void setValue(int);
int getValue() const;
};
If the member function is defined outside the class, both
the in-class declaration and the definition must have
the const
Concept

If a member variable is If a member function is


declared static, all declared static, it may
objects of that class be called before any
have access to that instances of the class
variable. are defined.
class Widget
{ First an example of
private: normal member variables
double price;
int quantity;
public:
Widget(double p, int q)
{ price = p; quantity = q; }
double getPrice() const
{ return price; }
int getQuantity() const
{ return quantity; }
};
class Widget
Assume a program creates 2
{ separate instances of the Widget
private: class
double price;
int quantity;
public: Widget w1(14.50, 100), w2(12.75, 500);
Widget(double p, int q)
{ price = p; quantity = q; }
double getPrice() const
{ return price; }
int getQuantity() const
{ return quantity; }
};
class Widget
{ getQuantity results in…
private:
double price;
int quantity; Widget w1(14.50, 100), w2(12.75, 500);
public:
Widget(double p, int q)
{ price = p; quantity = q; } cout << w1.getQuantity() << " " <<
double getPrice() const w2.getQuantity();
{ return price; }
int getQuantity() const
{ return quantity; }
}; 100 500
Static Member Variables
class StatDemo
{ To create a member variable
private: that is shared by all objects,
static int x; place the key word static in
int y; front of the variable declaration
public:
void setx(int a) { x = a; }
void sety(int b) { y = b; }
int getx() const { return x; }
int gety() const { return y; }
};
class StatDemo
{ Static Member Variables
private:
static int x; Next, place a separate
int y; definition of the variable
public: outside the class
void setx(int a) { x = a; }
void sety(int b) { y = b; }
int getx() const { return x; }
int gety() const { return y; } Member variable X will be shared by all
}; objects of the StatDemo class.
int StatDemo::x;
When one class object puts a value in X, it will
appear in all other StatDemo objects.
StatDemo obj1, obj2; class StatDemo
obj1.setx(5); {
private:
obj1.sety(10); static int x;
obj2.sety(20); int y;
cout << "x: " << obj1.getx() << " " << obj2.getx() << endl;
cout << "y: " << obj1.gety() << " " << obj2.gety() << endl;

m p l e
xa
Co de e

x: 5 5
y: 10 20
#ifndef BUDGET_H Code
E
a der
#define BUDGET_H static xample u
He mem sing
ber v
file class Budget ariab
le
{
private:
static double corpBudget;
double divBudget;
public:
Budget() { divBudget = 0; }
void addBudget(double b)
{ divBudget += b; corpBudget += divBudget; }
double getDivBudget() const { return divBudget; }
double getCorpBudget() const { return corpBudget; }
};
#endif
double Budget::corpBudget = 0; 🡨 initialize static var outside class
int main()
{
const int N_DIVISIONS = 4;
Budget divisions[N_DIVISIONS]; 🡨 4-element array of division objects

for (int count = 0; count < N_DIVISIONS; count++) Enter the budget request for division 1:
{ 102000[Enter]
Enter the budget request for division 2:
double bud;
201000[Enter]
cout << "Enter the budget request for division ";
Enter the budget request for division 3:
cout << (count + 1) << ": "; 570000[Enter]
cin >> bud; Enter the budget request for division 4:
divisions[count].addBudget(bud); 100100[Enter]
}
cout << setprecision(2);
Here are the division budget requests:
cout << showpoint << fixed;
Division 1 $ 102000.00
cout << "\nHere are the division budget requests:\n";
Division 2 $ 201000.00
for (int count = 0; count < N_DIVISIONS; count++) Division 3 $ 570000.00
{ Division 4 $ 100100.00
cout << "Division " << (count + 1) << "\t$ "; corpBudget
Total Budget Requests: $ 973100.00
cout << divisions[count].getDivBudget() << endl;
}
cout << "Total Budget Requests:\t$ "; divBudget divBudget
cout << divisions[0].getCorpBudget() << endl;🡨could use any index here
Concept

Static member functions do NOT


need an object instance in order
to be executed

Static member functions are


normally used to work with
static member variables
Static Member Functions

Declared static by prefixing its declaration


with the key word static

static <return type><function name>(<parameter list>)

Note: static member functions can ONLY work with


static member variables
Code Example – modifying the budget program
• Will now ask the user to enter the main office’s budget request before
any division requests are entered.

• The Budget class will be modified to include a static member function


named mainOffice.

• This function adds its argument to the static corpBudget variable and is
called before any instance of the Budget class is defined.

• The getCorpBudget() function will also be made static.


#ifndef BUDGET_H b ud g
#define BUDGET_H et2.h
h eade
class Budget r file
{ getCo
rpBu
private: beca dget
u se i t i s static
static double corpBudget; static only
double divBudget; varia work
bles s with
public:
Budget() { divBudget = 0; }
void addBudget(double b)
{ divBudget += b; corpBudget += divBudget; }
double getDivBudget() const { return divBudget; }
static double getCorpBudget() { return corpBudget; }
static void mainOffice(double);
};
#endif
b ud g
et2.c
pp im p le
ment
#include "budget2.h" ation
file
// Definition of the static member of Budget class
double Budget::corpBudget = 0;

//**********************************************************
// Definition of static member function mainOffice *
// This function adds the main office's budget request to *
// the corpBudget variable. *
//**********************************************************
void Budget::mainOffice(double budReq)
{
corpBudget += budReq;
}
const int N_DIVISIONS = 4;
// Get the budget requests for each division
cout << "Enter the main office's budget request: ";
double amount;
cin >> amount;
// Call the static member function of the Budget class
Budget::mainOffice(amount); 🡨 before object instantiation
// Create instances of the Budget class
Budget divisions[N_DIVISIONS];
for (int count = 0; count < N_DIVISIONS; count++)
{
double bud;

cout << "Enter the budget request for division ";


cout << (count + 1) << ": ";
cin >> bud;
divisions[count].addBudget(bud);
}
// Display the budget for each division
cout << setprecision(2);
cout<< showpoint << fixed;
cout << "\nHere are the division budget requests:\n";
for (int count = 0; count < N_DIVISIONS; count++)
{
cout << "\tDivision " << (count + 1) << "\t$ ";
cout << divisions[count].getDivBudget() << endl;
}

// Print total budget requests


cout << "Total Requests (including main office): $ ";
cout << Budget::getCorpBudget() << endl;
return 0;
Concept

A friend is a function
that is NOT a member of
a class but has access to
the private members of
the class
“Friend” notes
Private members are hidden from all parts of the program outside the class, and
accessing them requires a call to a public member function.

Sometimes you will want to create an exception to that rule.

A friend function is a function that is NOT a member of a class but that has access
to the class’s private members.

In other words, a friend function is treated as if it were a member of the class


Friends
A function is declared a friend by placing the key word friend
in front of a prototype of the function

friend <return type><function name>(<parameter type list>);

Note: A friend function can be a regular stand-alone function,


or it can be a member of another class
class Budget
{ addBu
dget f
of ano unctio
private: ther c n
Aux, lass,
static double corpBudget; has be
declar en
double divBudget; ed a f
riend:
public:
Budget() { divBudget = 0; }
void addBudget(double b)
{ divBudget += b; corpBudget += divBudget; }
double getDivBudget() const { return divBudget; }
static double getCorpBudget() { return corpBudget; }
static void mainOffice(double);
friend void Aux::addBudget(double); // A friend
};
Adding onto the budget code…

• Let’s assume another class Aux represents a division’s auxiliary


office, perhaps in another country.

• The auxiliary office makes a separate budget request, which must


be added to the overall corporate budget.

• The friend declaration of the Aux::addBudget function tells the


compiler that the function is to be granted access to Budget’s
private members
class Aux {
New Auxiliary class
private:
double auxBudget;
addBudget (friend of
public:
Aux() { auxBudget = 0; } Budget class) function
void addBudget(double);
double getDivBudget() { return auxBudget; }
};
void Aux::addBudget(double b) {
auxBudget += b;
Budget::corpBudget += auxBudget; }
const int N_DIVISIONS = 4;
cout << "Enter the main office's budget request: ";
double amount;
cin >> amount;
Budget::mainOffice(amount);

Budget divisions[N_DIVISIONS];
Aux auxOffices[N_DIVISIONS];

cout << "\nEnter the budget requests for the divisions and "
<< "\ntheir auxiliary offices as prompted:\n";
for (int count = 0; count < N_DIVISIONS; count++)
{
double bud;
cout << "Division " << (count + 1) << ": ";
cin >> bud;
divisions[count].addBudget(bud);
cout << "Division " << (count + 1) << "'s auxiliary office: ";
cin >> bud;
auxOffices[count].addBudget(bud);
}
cout << setprecision(2);
cout << showpoint << fixed;
cout << "Here are the division budget requests:\n";
for (int count = 0; count < N_DIVISIONS; count++)
{
cout << "\tDivision: " << (count + 1) << "\t\t\t$ ";
cout << setw(7);
cout << divisions[count].getDivBudget() << endl;
cout << "\tAuxiliary Office of Division " << (count+1);
cout << "\t$ ";
cout << auxOffices[count].getDivBudget() << endl;
}
cout << "\tTotal Requests (including main office): $ ";
cout << Budget::getCorpBudget() << endl;
Concept

The = operator may be By default, each


used to assign one member of one object is
object to another, or to copied to its
initialize one object with counterpart in the other
another object’s data. object.
Using the = sign

Objects may be assigned to each other


just like other variables (except arrays)
class Rectangle
{
private: Rectang
le class
double width, length; review
public:
Rectangle(double width, double length)
{
this->width = width;
this->length = length;
}
double getWidth() const { return width; }
double getLength() const { return length; }
void output() const
{
cout << "Width is " << width << ", "
<< "Length is " << length << endl;
}
};
Rectangle box1(10, 20), box2(5, 10); Obj
ec t
assi
cout << "Before the assignment:\n"; gn m
ent
cout << "Box 1 data:\t"; box1.output(); usin
cout << "Box 2 data:\t"; box2.output(); g =
box2 = box1;

cout << "\nAfter the assignment:\n";


cout << "Box 1 data:\t"; box1.output(); Before the assignment:
Box 1 data: Width is 10, Length is 20
cout << "Box 2 data:\t"; box2.output();
Box 2 data: Width is 5, Length is 10

box2 = box1 copied the width and


length variables of box1 into the After the assignment:
Box 1 data: Width is 10, Length is 20
width and length variables of box2 Box 2 data: Width is 10, Length is 20
Memberwise assignment
• Memberwise assignment also occurs when one
object is initialized with another object’s values

Rectangle box1(10, 50);


Rectangle box2 = box1;
Concept
A copy constructor is a special
constructor that is called
whenever a new object is
created and initialized with the
data of another object of the
same class
Creating an object with data from another objects

Mary and Joan An address object Makes sense to


for Mary has initialize Joan’s
live in the same already been address object to a
house created copy of Mary’s
class Address
{
private:
string street;
public:
Address() { street = ""; }
Address(string st) { setStreet(st); }
void setStreet(string st) { street = st; }
string getStreet() const { return street; }
};

Address mary("123 Main St");


Address joan = mary;
class Address
{
private: Address mary("123 Main St");
string street;
public: Address joan = mary;
Address() { street = ""; }
Address(string st) { setStreet(st); }
void setStreet(string st) { street = st; }
string getStreet() const { return street; }
};

Recall: A constructor executes whenever an object is being created

When an object is created AND initialized with another object of the


same class, the compiler automatically calls a special constructor,
called the copy constructor
Default Copy Constructor

If you do not “code” a It copies the data of the


copy constructor, then existing object to the
the compiler new object using
automatically calls a memberwise
default copy constructor assignment
Default copy constructor notes

Most of the time,


But, sometimes the
the default provides
behavior is not
the behavior that
what we expect
we want
class NumberArray For flexibility,
{ this class cont
pointer to an ain s a
private: array instead
directly conta of
double *aPtr; ining the arra
y itself
int arraySize;

public:
NumberArray(int size, double value);

// ~NumberArray(){ if (arraySize > 0) delete [] aPtr;}


void print() const;
void setValue(double value);
};
class NumberArray Constructor a
{ llocates an ar
specified size ray of a
private: , then sets all
entries of the the
double *aPtr; array to a give
n value
int arraySize;

public:
NumberArray(int size, double value);

// ~NumberArray(){ if (arraySize > 0) delete [] aPtr;}


void print() const;
void setValue(double value);
};
class NumberArray
{ Destructor de
private: allocates the
commented o array but is
double *aPtr; ut to avoid pr
caused by the oblems
int arraySize; default copy c
onstructor
public:
NumberArray(int size, double value);

// ~NumberArray(){ if (arraySize > 0) delete [] aPtr;}


void print() const;
void setValue(double value);
};
NumberArray::NumberArray(int size, double value)
Num
{
be rA
arraySize = size;
impl rray
aPtr = new double[arraySize];
e me Class
setValue(value);
ntati
}
//******************************************************* on
//Sets all the entries of the array to the same value. *
//*******************************************************
void NumberArray::setValue(double value)
{
for(int index = 0; index < arraySize; index++)
aPtr[index] = value;
}
//***************************************
//Prints all the entries of the array. *
//***************************************
void NumberArray::print() const
{
for(int index = 0; index < arraySize; index++)
cout << aPtr[index] << " ";
}
NumberArray first(3, 10.5);
Value stored in first object is 10.50 10.50 10.50
Value stored in second object is 10.50 10.50 10.50
// Make a copy of the object Only the value in second object will be changed.
NumberArray second = first;
Value stored in first object is 20.50 20.50 20.50
// Display the values of the two objects Value stored in second object is 20.50 20.50 20.50
cout << setprecision(2) << fixed << showpoint;
cout << "Value stored in first object is ";
first.print();
cout << endl << "Value stored in second object is ";
second.print();
cout << endl << "Only the value in second object "
pe n
hap
<< "will be changed." << endl;

d to
// Now change the value stored in the second object
e c te
second.setValue(20.5);
exp
we
at
// Display the values stored in the two objects
wh
cout << "Value stored in first object is ";
first.print();
Not
cout << endl << "Value stored in second object is ";
second.print();
NumberArray second = first;
Memberwise assignment performed by the default copy constructor
copies the value of the pointer in the first object to the pointer in the
second object, leaving both pointers pointing to the same data
More bad news…

The fact that the two pointers point to the same memory
location will also cause problems when the destructors for the
two objects try to deallocate the same memory
Conclusion…
In general, classes with pointer members will NOT behave
correctly under the default copy constructor provided by the
compiler.

They must be provided with a copy constructor written by the


programmer.
Programmer-defined Copy Constructors
• Must have a single parameter that is a reference to the same
class. Prototype shown below:

NumberArray::NumberArray(const NumberArray &obj)


NumberArray second = first;
The copy constructor avoids the problems of the default
copy constructor by allocating separate memory for the
pointer of the new object before doing the copy:

NumberArray::NumberArray(const NumberArray &obj)


{
arraySize = obj.arraySize;
aPtr = new double[arraySize]; first
for(int index = 0; index < arraySize; index++)
aPtr[index] = obj.aPtr[index];
}
Last thoughts on copy constructors

Copy constructors are also automatically called when a function call receives a value
parameter of the class type (making a copy of course)

fun(box);

void fun(Rectangle rect)


{
}

It is not called if it is passed by reference (&)


Code now works properly with the
programmer-coded copy constructor
Value stored in first object is 10.50 10.50 10.50
Value stored in second object is 10.50 10.50 10.50
Only the value in second object will be changed.
Value stored in first object is 10.50 10.50 10.50
Value stored in second object is 20.50 20.50 20.50
Concept
C++ allows you to redefine
how standard operators
work when used with class
objects
Why overload operators?

Another reason is to
One reason is to solve
give your class
problems that occur
more/easier ways to
from memberwise
work with the
copying/assignments
individual objects
Remember copy constructors?

Used programmer-defined copy constructor to fix the issue of


memberwise assignment when an object was initialized with another
object

Often, we run into the same problem with object assignment


Memberwise assignment issue

• We fixed this issue 🡪 NumberArray first = second;

• What about this one?

NumberArray first(3, 10.5);


NumberArray second(5, 20.5);
first = second;
Memberwise assignment issue
NumberArray first(3, 10.5);
NumberArray second(5, 20.5);
first = second;

Below is what we think it’s going to do…

20.5 20.5 20.5 20.5 20.5

20.5 20.5 20.5 20.5 20.5


Memberwise assignment issue
NumberArray first(3, 10.5);
NumberArray second(5, 20.5);
first = second;

But, C++ performs memberwise copy leaving pointers


in both objects pointing to the same member

20.5 20.5 20.5 20.5 20.5


How do we fix this?
NumberArray first(3, 10.5);
NumberArray second(5, 20.5);
first = second;

Can’t use copy constructor to fix this one because copy


constructors only run when an object is being initialized
at creation time

20.5 20.5 20.5 20.5 20.5


Copy constructors NOT called in an assignment

NumberArray second = first; // copy constructor called

second = first; // copy constructor NOT called


The fix!

Modify the behavior


of the assignment We will supply a We will be
operator (=) so it does
something other than different version overloading
a memberwise of the = operator the operator
assignment.
Solution: define an operator function called operator=
as a member function of the class
class NumberArray
{
private:
double *aPtr;
int arraySize;
public:
void operator=(const NumberArray &right); // Overloaded operator
NumberArray(const NumberArray &);
NumberArray(int size, double value);
~NumberArray() { if (arraySize > 0) delete [ ] aPtr; }
void print() const;
void setValue(double value);
};
Same syntax as a normal class function: Left operand is the
current object of the
void setBalance(double balance) class and the parameter
passed is the right
double getBalance(); operand
Parameters to operator functions do NOT have to be passed by
reference, nor do they have to be declared const.

Reference (&) parameter here is for efficiency. Reference


parameters avoid the overhead of copying the object being
passed. Const is used to protect the parameter from change
Illustrating what’s happening with the function call
NumberArray left(3,10.5);
NumberArray right(5, 20.5);

left.operator=(right); 🡨 function call

left = right 🡨 compiler lets us


use this more conventional notation
Assignment Operator’s Return Value
Why is the function returning something?

To be consistent with C++’s built-in assignment operator, which allows


cascaded assignment statements like:

a=b=c
Implementation of assignment operator

• If we have something like this: x = x


• Then no need to do any copying, right?
• Example 🡪 first = first;

• We need to test the address (this) of the


left side argument to the address of the
right side
Implementation of assignment operator

if (this != &right)
then go ahead and copy the
object…
NumberArray& NumberArray::operator=(const NumberArray &right) {
if (this != &right)
{
if (arraySize > 0)
{
delete [] aPtr; first = second;
}
arraySize = right.arraySize;
aPtr = new double[arraySize];
for (int index = 0; index < arraySize; index++)
{
aPtr[index] = right.aPtr[index];
}
}
return *this; 10.5 10.5 10.5
}

20.5 20.5 20.5 20.5 20.5


Wrapping it up
• In general, classes that allocate dynamic memory
in a constructor should always do 3 things:

1. Define a destructor,
2. Define a copy constructor
3. Define a copy assignment operator
class NumberArray {
private: Entire NumberArray code fixed
double *aPtr;
int arraySize; Header
public: file
// Copy assignment and copy constructor
NumberArray& operator=(const NumberArray &right);
NumberArray(const NumberArray &);

// Other constructor and Destructor


NumberArray(int size, double value);
~NumberArray() { if (arraySize > 0) delete [ ] aPtr; }

void print() const;


void setValue(double value);
};
#include <iostream>
#include "overload.h"
using namespace std;
Entire NumberArray code fixed
//***************************************************
//The overloaded operator function for assignment. * Implem
//*************************************************** entatio
NumberArray& NumberArray::operator=(const NumberArray &right) n file
{
if (this != &right)
{
if (arraySize > 0)
{
delete [] aPtr;
}
arraySize = right.arraySize;
aPtr = new double[arraySize];
for (int index = 0; index < arraySize; index++)
{
aPtr[index] = right.aPtr[index];
}
}
return *this;
}
Entire NumberArray code fixed
Implem
entatio
//********************************************** n file
//Copy constructor. *
//**********************************************
NumberArray::NumberArray(const NumberArray &obj)
{
arraySize = obj.arraySize;
aPtr = new double[arraySize];
for(int index = 0; index < arraySize; index++)
{
aPtr[index] = obj.aPtr[index];
}
}
//********************************************** Entire NumberArray code fixed
//Constructor. *
//********************************************** Implem
NumberArray::NumberArray(int size1, double value) entatio
{
n file
arraySize = size1;
aPtr = new double[arraySize];
setValue(value);
}

//****************************************************
//Sets the value stored in all entries of the array. *
//****************************************************
void NumberArray::setValue(double value)
{
for(int index = 0; index < arraySize; index++)
{
aPtr[index] = value;
}
}
//*************************************** Entire NumberArray code fixed
//Print out all entries in the array. *
//*************************************** Implem
entatio
void NumberArray::print() const n file
{
for(int index = 0; index < arraySize; index++)
{
cout << aPtr[index] << " ";
}
}
#include <iostream>
Entire NumberArray code fixed
#include <iomanip>
#include "overload.h" Testing
program
using namespace std;

int main()
{
NumberArray first(3, 10.5);
NumberArray second(5, 20.5);

// Display the values of the two objects


cout << setprecision(2) << fixed << showpoint;
cout << "First object's data is ";
first.print();
cout << endl << "Second object's data is ";
second.print();
Entire NumberArray code fixed
Testing
program
// Call the overloaded operator
cout << "\nNow we will assign the second object "
<< "to the first." << endl;
first = second;

// Display the new values of the two objects


cout << "First object's data is ";
first.print();
cout << endl << "The second object's data is ";
second.print();
Entire NumberArray code fixed
Testing
program

First object's data is 10.50 10.50 10.50


Second object's data is 20.50 20.50 20.50 20.50 20.50

Now we will assign the second object to the first.

First object's data is 20.50 20.50 20.50 20.50 20.50


The second object's data is 20.50 20.50 20.50 20.50 20.50
Overloading other operators
• C++ allows you to overload other operators
besides the assignment (=) operator

• You might want to overload some built-in


operators to make them work with your classes
Example
• You have a class named Date

• Date class has day, month, and year member variables

• You have a member function called add

• Add member function adds a number of days to the date and


adjusts the member variables if the date goes to another
month or year
Example

• Day today(10,30,2021); 🡨 create date object

• today.add(5); 🡪 11/4/2021 🡨 add 5 days

• What if you could do this? 🡪 today += 5;


Did you know you’ve already used an
overloaded operator? 🡪 12 / 5
• The / operator performs two types of division: floating-point
and integer.

• If one of the operands is a floating-point type, the result will


be a floating-point value.

• If both of the / operator’s operands are integers, however,


the result is an integer, and the fractional part is thrown
away.
Interesting quirks about operator overloading
• Just cuz you can do it doesn’t mean you should… ☺

• You could change an operators entire meaning

• Nothing to prevent you from changing the = symbol


from an assignment operator to a “display” operator…
class Weird
{ Weird a(5), b(10);
private: a = b;
int value;
public: Running this program
Weird(int v) would result in the
{value = v; } value 10 displaying
void operator=(const Weird &right) instead of assigning
{ cout << right.value << endl; } 10 to the member
}; variable a
Most operators can be overloaded…

• Here’s the ones that can NOT:

?: . .* :: sizeof
Two approaches to Operator Overloading
1. Make the overloaded operator a member function of the class.
• This allows the operator function access to private members of the
class. It also allows the function to use the implicit this pointer
parameter to access the calling object.

2. Make the overloaded member function a separate, stand-


alone function.
• When overloaded in this manner, the operator function must be
declared a friend of the class to have access to the private members
of the class.
Member functions vs stand-alone functions
• Some operators, such as the stream input and
output operators >> and <<, must be overloaded
as stand-alone functions.

• Other operators may be overloaded either as


member functions or stand-alone functions.
class Length {
private: Length class Allows user to enter
int len_inches;
example feet and inches even
public: though the one
Length(int feet, int inches)
{ member variable is
setLength(feet, inches); inches
}
Length(int inches) { len_inches = inches; }
int getFeet() const { return len_inches / 12; }
Has member functions
int getInches() const { return len_inches % 12; } to allow feet and
void setLength(int feet, int inches) Inches to be retrieved
{ separately
len_inches = 12 *feet + inches;
}
};
Program requirements
• Clients of the class must be able to add and subtract
measurements 🡪 objectC = objectA + objectB

• In addition, they should be able to compare two


measurements to see if they are equal or if one of them is
less or greater than the other 🡪 if (objectA == objectB)

• We will provide these capabilities by overloading the


operators +, −, <, and == as stand-alone functions.
Step one: Add declarations to Length class
friend Length operator+(Length a, Length b);
friend Length operator−(Length a, Length b);
friend bool operator<(Length a, Length b);
friend bool operator==(Length a, Length b);

Stand alone functions must be “friends”

Next slide breaks this down…


Step one: Add declarations to Length class
friend Length operator+(Length a, Length b);
friend Length operator−(Length a, Length b);

If we need to perform c = a + b then the right side is


composed of 2 parameters (a and b)

Also, we need a return type because objectC is receiving


the result of the addition
Step one: Add declarations to Length class

friend bool operator<(Length a, Length b);


friend bool operator==(Length a, Length b);

For < and ==, we need a return type of


boolean after determining whether objectA
is equal or less than objectB
Step Two: implement the functions (first the +)
Length operator+(Length a, Length b)
{
Length result(a.len_inches + b.len_inches);
return result;
}
Create a new Length object initializing it to objectA’s len_inches member
variable plus objectB’s len_inches member variable
Remember doing this in your last course to improve efficiency?

int addNumbers(int a, int b){


int c;
c = a + b;
return c; int addNumbers(int a, int b){
} return a + b;
}
Step Two: implement the functions (first the +)
Length operator+(Length a, Length b)
{
return Length(a.len_inches + b.len_inches);
return result; 🡪 temp result object unnecessary
}

Another more efficient code example


Step Two: implement the functions (now the ==)
bool operator==(Length a, Length b)
{
bool temp = false;
if (a.len_inches == b.len_inches)
temp = true;
return temp;
}

Test the two object’s len_inches member variables to see if they are equal in
value. Return the result.
Step Two: implement the functions (now the ==)
bool operator==(Length a, Length b)
{
return a.len_inches == b.len_inches;
}

Clean up the code for efficiency


class Length
{
private:
int len_inches;
public:
Length(int feet, int inches)
{
setLength(feet, inches);
}
Length(int inches){ len_inches = inches; }
int getFeet() const { return len_inches / 12; }
int getInches() const { return len_inches % 12; }
void setLength(int feet, int inches)
{
len_inches = 12 *feet + inches;
}
friend Length operator+(Length a, Length b);
friend Length operator-(Length a, Length b);
friend bool operator< (Length a, Length b);
friend bool operator== (Length a, Length b);
};
//*************************************
// Overloaded operator + *
//*************************************
Length operator+(Length a, Length b)
{
return Length(a.len_inches + b.len_inches);
}

//*************************************
// Overloaded operator - *
//*************************************
Length operator-(Length a, Length b)
{
return Length(a.len_inches - b.len_inches);
}
//************************************
// Overloaded operator == *
//************************************
bool operator==(Length a, Length b)
{
return a.len_inches == b.len_inches;
}

//************************************
// Overloaded operator < *
//************************************
bool operator<(Length a, Length b)
{
return a.len_inches < b.len_inches;
}
Length first(0), second(0), third(0);
int f, i;
cout << "Enter a distance in feet and inches: ";
cin >> f >> i;
first.setLength(f, i);
cout << "Enter another distance in feet and inches: ";
cin >> f >> i;
second.setLength(f, i);
// Test the + and - operators
Enter a distance in feet and inches: 6 5
third = first + second; Enter another distance in feet and inches: 3 10
cout << "first + second = "; first + second = 10 feet, 3 inches.
cout << third.getFeet() << " feet, ";
cout << third.getInches() << " inches.\n";
first − second = 2 feet, 7 inches.
third = first - second; first == second = false
cout << "first - second = "; first < second = false
cout << third.getFeet() << " feet, ";
cout << third.getInches() << " inches.\n";
// Test the relational operators
cout << "first == second = ";
if (first == second) cout << "true"; else cout << "false";
cout << "\n";
cout << "first < second = ";
if (first < second) cout << "true"; else cout << "false";
cout << "\n";
How does the compiler interpret our code?

Length a(4, 2), b(1, 8), c(0);


c = a + b;

Length a(4, 2), b(1, 8), c(0);


c = operator+(a, b); 🡨 compiler sees this
What if we overloaded the + operator as a
member function instead of stand-alone?
Length operator+(Length a, Length b) 🡨 stand-alone version

class Length
{ Notice now we only
private: have one parameter
int len_inches;
public: As a member function,
// Modified declaration of operator+ the operator is passed
Length operator+(Length b);
// Rest of class not shown
a Length object through
}; the this implicit param
What if we overloaded the + operator as a
member function instead of stand-alone?
Length operator+(Length a, Length b) 🡨 stand-alone version

class Length
{ Length a(4, 2), b(1, 8), c(0);
private: c = a + b;
int len_inches;
public:
// Modified declaration of operator+ Length a(4, 2), b(1, 8), c(0);
Length operator+(Length b); c = a.operator+(b);
// Rest of class not shown
}; Compiler sees this now
What if we overloaded the + operator as a
member function instead of stand-alone?
Length operator+(Length a, Length b) 🡨 stand-alone version

When you write a + b, the left


operand of the overloaded + Length a(4, 2), b(1, 8), c(0);
operator becomes the object c = a + b;
through which the member
function is called, and the right Length a(4, 2), b(1, 8), c(0);
c = a.operator+(b);
operand becomes the explicit
parameter. Compiler sees this now
What if we overloaded the + operator as a
member function instead of stand-alone?

Length Length::operator+(Length b)
{
return Length(this−>len_inches + b.len_inches);
}
To sum up

• The addition operator (as well as other arithmetic


and relational operators) can be overloaded equally
well as member functions or as stand-alone
functions.

• It is generally better to overload binary operators


that take parameters of the same type as stand-
alone functions.
Overloading the Prefix ++ Operator (++b)
• We want to overload the prefix operator for the
Length class so that the expression ++b increments
the object b by adding 1 inch to its length and
returns the resulting object.

• We overload this operator as a member function.


This makes its single parameter implicit, so the
overloaded operator needs no parameters.
objectB = ++objectA
class Length
{ Compiler sees this:
private: objectA.operator++()
int len_inches;
public:
// Declaration of prefix ++ Length Length::operator++()
Length operator++(); {
// Rest of class not shown len_inches ++;
}; return *this;
}
Overloading the Postfix ++ Operator (b++)
• The postfix ++ operator will also increment the
length of b, but it returns the value that the
object had prior to being incremented
class Length{
private: objectB =objectA++
int len_inches; Length Length::operator++(int)
public: {
// Declaration of prefix ++ Length temp = *this;
Length operator++(int); len_inches ++;
// Rest of class not shown return temp;
}; }

Function now has a dummy parameter of type int that is


never used in the body of the function
class Length{
private: objectB =objectA++
int len_inches; Length Length::operator++(int)
public: {
// Declaration of prefix ++ Length temp = *this;
Length operator++(int); len_inches ++;
// Rest of class not shown return temp;
}; }

Need a temp variable to capture the value of the object


BEFORE it is incremented
Overloading the Stream Insertion (<<) and
Extraction Operators (>>)

• Overloading the stream insertion operator << is


convenient because it allows values of objects to
be converted into text and output to cout
Overloading the Stream Insertion (<<) and
Extraction Operators (>>)
• Instead of calling getter functions and formatting
cout code for output, you could simply do this:

Length b(4, 8), c(2, 5);


cout << b;
cout << b + c;
ostream &operator<<(ostream& out, Length a)
{
out << a.getFeet() << " feet, " << a.getInches() << " inches";
return out;
}
Why do we have a return type of ostream?

Again, to allow chained expressions like this:


cout << b << “ “ << b + c;
ostream &operator<<(ostream& out, Length a)
{
out << a.getFeet() << " feet, " << a.getInches() << " inches";
return out;
}
Nothing new here, just the operator symbol used
for the function name
ostream &operator<<(ostream& out, Length a)
{
out << a.getFeet() << " feet, " << a.getInches() << " inches";
return out;
}
cout << a; 🡨 expression

First parameter is the left side of the equation so


cout is of the type ostream and must be a reference
parameter (&)
ostream &operator<<(ostream& out, Length a)
{
out << a.getFeet() << " feet, " << a.getInches() << " inches";
return out;
}
cout << a; 🡨 expression

Second parameter is the right side of the equation so


a is an object of type Length. Must be a value param
Now overloading the stream input operator (>>) cin >> objectA
Not much different from stream insertion
istream &operator>>(istream& in, Length &a){
int feet, inches;
cout << "Enter feet: ";
in >> feet;
cout << "Enter inches: ";
in >> inches;

a.setLength(feet, inches);
return in; }
class Length {
private:
int len_inches;
public: Comp
le
Length(int feet, int inches) all ov te code f
erride or L e
{ s ngth
class
w ith
setLength(feet, inches);
}
Length(int inches){ len_inches = inches; }
int getFeet() const { return len_inches / 12; }
int getInches() const { return len_inches % 12; }
void setLength(int feet, int inches)
{
len_inches = 12 *feet + inches;
}
friend Length operator+(Length a, Length b);
friend Length operator-(Length a, Length b);
friend bool operator<(Length a, Length b);
friend bool operator==(Length a, Length b);
Length operator++();
Length operator++(int);
friend ostream &operator<<(ostream &out, Length a);
friend istream &operator>>(istream &in, Length &a);
};
//**********************************************
// Overloaded stream extraction operator >> *
//**********************************************
istream &operator>>(istream &in, Length &a)
{
// Prompt for and read the object data
int feet, inches;
cout << "Enter feet: ";
in >> feet;
cout << "Enter inches: ";
in >> inches;

// Modify the object a with the data and return


a.setLength(feet, inches);
return in;
}

//*********************************************
// Overloaded stream insertion operator << *
//*********************************************
ostream &operator<<(ostream& out, Length a)
{
out << a.getFeet() << " feet, " << a.getInches() << " inches";
return out;
}
//***********************************
// Overloaded prefix ++ operator *
//***********************************
Length Length::operator++()
{
len_inches ++;
return *this;
}

//***********************************
// Overloaded postfix ++ operator *
//***********************************
Length Length::operator++(int)
{
Length temp = *this;
len_inches ++;
return temp;
}
//*************************************
// Overloaded operator - *
//*************************************
Length operator+(Length a, Length b)
{
return Length(a.len_inches + b.len_inches);
}
//*************************************
// Overloaded operator - *
//*************************************
Length operator-(Length a, Length b)
{
return Length(a.len_inches - b.len_inches);
}
//************************************
// Overloaded operator == *
//************************************
bool operator==(Length a, Length b)
{
return a.len_inches == b.len_inches;
}
//************************************
// Overloaded operator < *
//************************************
bool operator<(Length a, Length b)
{
return a.len_inches < b.len_inches;
}
int main()
{
Length first(0), second(1, 9), c(0);

cout << "Demonstrating prefix ++ operator and output operator.\n";


for (int count = 0; count < 4; count++)
{
first = ++second;
cout << "First: " << first << ". Second: " << second << ".\n";
}
cout << "\nDemonstrating postfix ++ operator and output operator.\n";
for (int count = 0; count < 4; count++)
{
first = second++;
cout << "First: " << first << ". Second: " << second << ".\n";
}

cout << "\nDemonstrating input and output operators.\n";


cin >> c;
cout << "You entered " << c << "." << endl;
return 0;
}
Demonstrating prefix ++ operator and output operator.
First: 1 feet, 10 inches. Second: 1 feet, 10 inches.
First: 1 feet, 11 inches. Second: 1 feet, 11 inches.
First: 2 feet, 0 inches. Second: 2 feet, 0 inches.
First: 2 feet, 1 inches. Second: 2 feet, 1 inches.

Demonstrating postfix ++ operator and output operator.


First: 2 feet, 1 inches. Second: 2 feet, 2 inches.
First: 2 feet, 2 inches. Second: 2 feet, 3 inches.
First: 2 feet, 3 inches. Second: 2 feet, 4 inches.
First: 2 feet, 4 inches. Second: 2 feet, 5 inches.
Demonstrating input and output operators.
Enter feet: 3[Enter]
Enter inches: 4[Enter]
You entered 3 feet, 4 inches.

You might also like