0% found this document useful (0 votes)
50 views15 pages

Chapter 12

The document discusses operator overloading in C++. It explains that operator overloading allows programmers to redefine how standard operators work with class objects. It provides examples of overloading operators like +, -, *, and assignment (=). It also discusses topics like multiple assignment, unary operators, and using member functions versus non-member friend functions for operator overloading.

Uploaded by

Amudaria
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)
50 views15 pages

Chapter 12

The document discusses operator overloading in C++. It explains that operator overloading allows programmers to redefine how standard operators work with class objects. It provides examples of overloading operators like +, -, *, and assignment (=). It also discusses topics like multiple assignment, unary operators, and using member functions versus non-member friend functions for operator overloading.

Uploaded by

Amudaria
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/ 15

Chapter 12

Operator Overloading

12-1
Operator Overloading

We have looked at ways to enhance the features of C++ by using function overloading
and overriding. We are going to look at a way to use some common C++ operators to
work with class objects.

Operator Overloading- allows the programmer to redefine how standard operators


work with class objects.

We have been working with overloaded operators that are defined in the C++ libraries.

<<
- the stream-insertion operator
- bitwise left-shift operator

>>
- the stream-extraction operator
- the bitwise right-shift operator

*
- multiplication
- "is a pointer to"
- indirection operator (dereference)

+ and -
- these operators perform differently depending on whether they are operating on
integers, floating-point numbers, or pointers

The operators +, -, *, /, etc. are nothing more than functions that are called using a
different syntax for listing their arguments. The arguments are listed before and after the
operator rather than listed in parentheses after a function name. The job performed by
operator overloading could be performed by using explicit function calls, but operator
notation can sometimes be more clear.

value = a + b / c;

is easier to read than say

value = add(a, div(b,c));

12-2
- Use operator overloading when it makes a program clearer than accomplishing
the same operations with explicit function calls.

- Avoid excessive or inconsistent use of operator overloading as this can make a


program cryptic and difficult to read.

To use a C++ operator on class objects, the operator MUST be overloaded - - with two
exceptions. The assignment operator (=) and the address operator (&).

- The assignment operator may be used with every class without overloading it. The
default behavior for the operator is memberwise assignment of the data members of
the class (recall the necessity for a copy constructor).
- Likewise, the address operator does not need to be overloaded and will simply
return the address of the object in memory.

Operators are overloaded by writing a function definition (heading and body) just as we
have done thus far. The name of the function becomes operator followed by the symbol
you wish to overload. Everything else remains virtually the same.

operator-
operator*

In the copy constructor example we had a special constructor that would ensure that
dynamically allocated memory was actually copied rather than just the address. This
takes care of statements such as

Person p2 = p1; //object instantiation

but not statements such as

p2 = p1; //assignment of one object's data to another

We are going to need to overload the assignment operator so the behavior of the
assignment expression will be as expected. The function heading for functions that
overload operators is as follows:

void operator=(const Person& obj)

Just as with the copy constructor, a reference parameter is used so the compiler does not
make a copy and const so it cannot be changed.

12-3
The statement p2=p1; would cause p2's overloaded function to be called passing p1 as the
argument. The contents of p1 would be copied into p2. In other words, the object on the
left's member function is called with the object on the right as the argument.

class Person
{
public:
Person();
Person(char* nm, int age);
Person(const Person& obj)
~Person();
char* GetName()const;
int GetAge()const;
void SetData(char* nm, int age);
void operator=(const Person& obj);
private:
char* pName;
int pAge;
};

void Person::operator=(const Person& obj)


{
//release the dynamically allocated memory
delete [ ] pName;
//create the new array
pName = new char[strlen(obj.pName) + 1];
strcpy(pName, obj.pName);
pAge = obj.pAge;
}

12-4
int main()
{
Person p1("Sam Jones",25);
cout << "\n\n" << p1.GetName() << ' ' << p1.GetAge();
Person p3;
cout << "\n\n" << p3.GetName() << ' ' << p3.GetAge();
Person p2 = p1;
cout << "\n\n" << p2.GetName() << ' ' << p2.GetAge();
p2.SetData("Sally Smith",45);
cout << "\n\n" << p1.GetName() << ' ' << p1.GetAge();
cout << "\n\n" << p2.GetName() << ' ' << p2.GetAge();
p3=p1;
cout << "\n\n" << p3.GetName() << ' ' << p3.GetAge();
cin.ignore(100,'\n');
cin.get();
return 0;
}

Basic Rules

- You cannot change the precedence of an operator by overloading it. If you wish to
change the order of evaluation you must use parentheses.

- The associativity of an operator cannot be changed by overloading. For example, the


relationships

(a + b) + c = a + (b + c)

(a - b) - c != a - (b - c)

must remain true

- You cannot change the number of operands required for a particular operator.
- unary operators must have one operand
- binary operators must have two operands
- the C++ ternary operator ( ?: ) cannot be overloaded

- You cannot change the way an operator works on built-in types. For example, you
cannot change the way the * operator multiplies two integer values.

- You cannot create new operators by using a combination of existing operators. For
example, you cannot copy the FORTRAN version of exponentiation by attempting to
define ** in your programs.

- To prevent changes to the way operators behave on built-in types, at least one
argument of an operator function must be a class object or a reference to a class object.

12-5
- Operator overloading must be done explicitly for each operator. Assume you have
overloaded the addition operator and the assignment operator to allow the following:

firstObj = firstObj + secondObj;

This does not imply that the statement

firstObj += secondObj;

is a valid statement. The += operator would need to be overloaded explicitly.

Operator Overloading & friend Functions

When a member function is used to overload an operator, the leftmost operand must be
an object of the class or a reference to an object of the class. There are times when the
leftmost operand is an object of a different class or a built-in type. An example of this
would be the insertion and extraction (stream) operators. In such cases, the overloaded
function cannot be a member function. If the function requires access to private or
protected information, this function must be a friend of the class.

12-6
Multiple Assignment

The assignment operator in C++ supports multiple assignment. The statement

num1 = num2 = num3;

is valid. The value of num3 is stored in num2 and returned. The return value is then stored in
num1.

Let's go back to the Person class example.

void Person::operator=(const Person& obj)


{
//release the dynamically allocated memory
delete [ ] pName;
//create the new array
pName = new char[strlen(obj.pName) + 1];
strcpy(pName, obj.pName);
pAge = obj.pAge;
}

How should this function be changed so it can support multiple assignment?

12-7
Class Members or friend Functions?

Operator functions can be defined as member or non-member functions (depending on


the data type of the left operand). When a member function is used, if the operator is a
binary operator, the member function of the operand on the left is used. That is to say,
the member function uses the this pointer. The this pointer is a predefined pointer that
points to the calling object. Note, this is not the name of the calling object but rather the
name of a pointer that points to the calling object. You may not change the value of the
this pointer, it always points to the calling object.

class thisDemo
{
public:
void ShowVal();
private:
int val;
};

void thisDemo::ShowVal()
{
cout << val;
}

// same function using the this pointer


void thisDemo::ShowVal()
{
cout << this->val;
}

12-8
Consider a class that keeps track of an amount of money in dollars and cents.

class Money
{
public:
Money();
Money(int dlrs, int cnts);
void SetAmount(int dlrs, int cnts);
int GetDollars()const;
int GetCents()const;
void Adjust(); //adjusts amount when cents exceed 99 as well as
// handling negative values
Money operator+ (const Money& obj);
Money operator- (const Money& obj);
Money operator++();
Money operator++(int);
private:
int dollars;
int cents;
};

Why are there two versions of the unary ++ operator?

Because the ++ operator is a unary operator, there is no need for a __________________


______________. One version however has what is called a ___________________
parameter that is nameless. It is used to tell the compiler that this version of the function
is to be used in _________________ mode. Therefore, given two Money objects

money1 is equal to 2 dollars, 50 cents and


money2 is equal to 3 dollars and 10 cents the statement
money1 = ++money2 would result in
money1 containing 3 dollars and 11 cents and
money2 containing 3 dollars and 11 cents

function operator++( ) was called for this calculation

money1 is equal to 2 dollars, 50 cents and


money2 is equal to 3 dollars and 10 cents the statement
money1 = money2++ would result in
money1 containing 3 dollars and 10 cents and
money2 containing 3 dollars and 11 cents

function operator++(int) was called for this calculation

12-9
int main()
{
// Write a test program that adds two Money objects, subtracts two Money objects
// and adjusts the result as necessary. Given the following
// dollars cents dollars cents dollars cents
// 2 50 + 3 75 6 25
// 3 25 - 2 50 0 75
// 2 10 - 3 50 -1 -40

return 0;
}

Money::Money():dollars(0),cents(0) {}
Money::Money(int dlrs, int cnts):dollars(dlrs >= 0 ? dlrs : 0),
cents(cnts >= 0 ? cnts : 0) {}
void Money::SetAmount(int dlrs, int cnts)
{
dollars = (dlrs >= 0) ? dlrs : 0;
cents = (cnts >= 0 ? cnts : 0);
}
int Money::GetDollars()const
{
return dollars;
}
int Money::GetCents()const
{
return cents;
}

void Money::Adjust()
{

Money Money::operator+ (const Money& obj)


{

12-10
Money Money::operator- (const Money& obj)
{

// The prefix ++ operator


Money Money::operator++();
{
// increment the cents, adjust the dollars if necessary and return the dereferenced this pointer

// The postfix ++ operator


Money Money::operator++(int)
{
// create a temporary copy of the object, increment cents, adjust as necessary, and return the
// appropriate object

IMPLEMENT THESE FUNCTIONS. The shell for this program is called

moneyshell.cpp and is located in the class data folder on the network.

12-11
Overloading Stream Operators (<< and >>)
class PhoneNum
{
public:
PhoneNum(string ac, string exc, string line);
void GetPhoneNum()const;
private:
string areaCode;
string exchange;
string line;
};

int main()
{
PhoneNum myPhone("949","582","4820");
string aCode, exch, line;
cout << "Enter your area code: ";
cin >> aCode;
cout << "Enter your exchange: " ;
cin >> exch;
cout << "Enter your line number: ";
cin >> line;
PhoneNum yourPhone(aCode,exch,line);

cout << "\n\nMy phone number: \n";


myPhone.GetPhoneNum();
cout << "Your phone number: \n";
yourPhone.GetPhoneNum();
return 0;
}

PhoneNum::PhoneNum(string aC, string exc, string line):areaCode(aC),


exchange(exc), line(line) { }

void PhoneNum::GetPhoneNum()const
{
cout << '(' << areaCode << ") " << exchange << '-' << line << "\n\n";
}

12-12
It would be extremely convenient to replace the several lines of code associated with
obtaining a phone number with the statement

cin >> thePhoneNum;

Recall, if the operand on the left is an object of another class or a built-in data type, the
operator function must be implemented as a ___________________________ function.
To allow the function access to the private data without being forced to use the get and
set methods, it is a good idea to make this function a ___________________ of the class.
This function is not part of the class so although it may be declared anywhere in the class,
good style usually dictates that it be declared ___________________________________
_____________________________.

Let's take a look at a few of the details. The insertion and extraction operators have many
of the same properties of operators such as +, -, * etc. The insertion operator has a stream
variable as the left operand and a string literal, variable, or expression as the right
operand. Overloading this operator involves a little more thought than the arithmetic
operators. If we want to allow for expressions such as

cin >> thePhoneNumber;

What should the overloaded operator function return?

A ________________________ is not a valid return type as it might be an entire file, the


keyboard, or even the screen. Therefore, we want a _______________________ to the
file, keyboard, or screen. This is done by adding an _________________ to the name of
the return type.

12-13
class PhoneNum
{

public:
PhoneNum();
PhoneNum(string ac, string exc, string line);
void GetPhoneNum()const;
private:
string areaCode;
string exchange;
string line;
};

int main()
{
PhoneNum myPhone("949","582","4820");
PhoneNum yourPhone;
cout << "Enter your phone number in the form (xxx) xxx-xxxx: ";
cin >> yourPhone;

cout << "\n\nMy phone number: \n";


myPhone.GetPhoneNum();
cout << "Your phone number: \n";
yourPhone.GetPhoneNum();
return 0;
}

PhoneNum::PhoneNum() { }

PhoneNum::PhoneNum(string aC, string exc, string line):areaCode(aC),


exchange(exc), line(line) { }

12-14
istream& operator >>(istream& input, PhoneNum& num)
{

void PhoneNum::GetPhoneNum()const
{
cout << '(' << areaCode << ") " << exchange << '-' << line << "\n\n";
}

12-15

You might also like