0% found this document useful (0 votes)
40 views

9 Operator Overloading

This document discusses operator overloading in C++. It explains that operators can be overloaded by defining operator functions or methods with the operator keyword. For binary operators like addition, the function takes two parameters, while the method takes one parameter. The document provides an example of overloading the addition operator for a Complex class to add two complex numbers. It demonstrates overloading using both a friend function and a member method. Defining the operator resolves ambiguities when using the operator with instances of the class.

Uploaded by

Utsav Vedant
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)
40 views

9 Operator Overloading

This document discusses operator overloading in C++. It explains that operators can be overloaded by defining operator functions or methods with the operator keyword. For binary operators like addition, the function takes two parameters, while the method takes one parameter. The document provides an example of overloading the addition operator for a Complex class to add two complex numbers. It demonstrates overloading using both a friend function and a member method. Defining the operator resolves ambiguities when using the operator with instances of the class.

Uploaded by

Utsav Vedant
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/ 21

Object Oriented Programming with C++

9. Operator Overloading

By: Prof. Pandav Patel

Third Semester, August 2020


Computer Engineering Department
Dharmsinh Desai University
Operator Overloading
#include<iostream> Complex addf(Complex &c1, Complex &c2) {
cout << "Inside friend function" << endl;
using std::cout; Complex result; This is a normal function, it is
using std::endl; result.re = c1.re + c2.re; not a method. Hence it needs to
result.im = c1.im + c2.im;
class Complex { return result; be declared as friend function
double re, im; } because it accesses private
public: data memebers
Complex(double re = 0, double im = 0) { int main() {
this->re = re; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4;
this->im = im; c3 = c1.addm(c2);
} c4 = addf(c1, c2);
void print() { // error: no match for ‘operator+’
cout << re << " + j" << im << endl; // (operand types are ‘Complex’ and ‘Complex
} // c3 = c1 + c2; This results in error as +
Complex addm(Complex &c) { c3.print();
cout << "Inside method" << endl; c4.print();
operator has not yet been
Complex result; return 0; overloaded to operate on two
result.re = this->re + c.re; } complex numbers. Hence
result.im = this->im + c.im; compiler does not know which
return result;
} Inside method function or method to call
// declared as friend function because re and im are private Inside friend function
// if they were public, we dont need to declare it as friend 3.3 + j3.3
friend Complex addf(Complex &c1, Complex &c2);
}; 3.3 + j3.3
Operator Overloading
#include<iostream> Complex operator+(Complex &c1, Complex &c2) {
cout << "Inside friend function" << endl;
using std::cout; Complex result;
using std::endl; result.re = c1.re + c2.re;
result.im = c1.im + c2.im;
class Complex { return result;
double re, im; }
public:
Complex(double re = 0, double im = 0) { int main() {
this->re = re; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4;
this->im = im; c3 = c1.addm(c2);
} c4 = c1 + c2;
void print() {
cout << re << " + j" << im << endl;
}
Complex addm(Complex &c) { c3.print();
cout << "Inside method" << endl; c4.print();
Complex result; return 0;
result.re = this->re + c.re; }
result.im = this->im + c.im;
return result;
} Inside method
// declared as friend function because re and im are private Inside friend function
// if they were public, we dont need to declare it as friend 3.3 + j3.3
friend Complex operator+(Complex &c1, Complex &c2);
}; 3.3 + j3.3
Operator Overloading
#include<iostream> Complex operator+(Complex &c1, Complex &c2) {
cout << "Inside friend function" << endl;
using std::cout; Complex result;
using std::endl; result.re = c1.re + c2.re;
result.im = c1.im + c2.im;
class Complex { return result;
double re, im; }
public:
Complex(double re = 0, double im = 0) { int main() {
this->re = re; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4;
this->im = im; c3 = c1 + c2;
} c4 = c1 + c2;
void print() { // Above two operators will result in error
cout << re << " + j" << im << endl; // error: ambiguous overload for ‘operator+’
} // (operand types are ‘Complex’ and ‘Complex’)
Complex operator+(Complex &c) { c3.print();
cout << "Inside method" << endl; c4.print();
Complex result; return 0;
result.re = this->re + c.re; }
result.im = this->im + c.im;
return result;
}
// declared as friend function because re and im are private
// if they were public, we dont need to declare it as friend
friend Complex operator+(Complex &c1, Complex &c2);
};
Operator Overloading
#include<iostream> Complex addf(Complex &c1, Complex &c2) {
cout << "Inside friend function" << endl;
using std::cout; Complex result;
using std::endl; result.re = c1.re + c2.re;
result.im = c1.im + c2.im;
class Complex { return result;
double re, im; }
public:
Complex(double re = 0, double im = 0) { int main() {
this->re = re; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4;
this->im = im; c3 = c1 + c2;
} C4 = addf(c1 ,c2);
void print() {
cout << re << " + j" << im << endl;
}
Complex operator+(Complex &c) { c3.print();
cout << "Inside method" << endl; c4.print();
Complex result; return 0;
result.re = this->re + c.re; }
result.im = this->im + c.im;
return result;
} Inside method
// declared as friend function because re and im are private Inside friend function
// if they were public, we dont need to declare it as friend 3.3 + j3.3
friend Complex addf(Complex &c1, Complex &c2);
}; 3.3 + j3.3
Operator Overloading

New keyword – operator

In order to overload operator, operator function/method needs to be defined

Name of the operator function/method starts with keyword operator, followed by operator
symbol to be overloaded

For example, in order to overload operator ‘+’ to add two complex numbers (c1 + c2)

Complex operator+(Complex &c1, Complex &c2); // overload using function

Complex Complex::operator+(Complex &c); // overload using method

To overload binary operator – function takes two parameters, while method takes one

To overload unary operator – function takes one parameters, while method takes zero


Operator functions are implicit for predefined operators of built-in types and can not be
redefined


Operator functions/methods can be defined for struct and union types as well

Operator functions can be defined for enum type too

At least one argument of an operator function must be of a user-defined type (struct, class,
union, enum), or a reference to one.
Operator Overloading
#include<iostream> Complex operator*(Complex c1, int num) {
cout << "Inside friend function" << endl;
using std::cout; Complex result;
using std::endl; result.re = c1.re * num;
result.im = c1.im * num;
class Complex { return result;
double re, im; }
public:
Complex(double re = 0, double im = 0) { int main() {
this->re = re; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4;
this->im = im; c3 = c1 + c2;
} c4 = c3 * 2;
void print() { c3.print();
cout << re << " + j" << im << endl; c4.print();
} return 0;
Complex operator+(Complex &c) { }
cout << "Inside method" << endl;
Complex result; Inside method
result.re = this->re + c.re;
result.im = this->im + c.im; Inside friend function
return result; 3.3 + j3.3
} 6.6 + j6.6
friend Complex operator*(Complex c1, int num);
};

Operator functions/methods can be defined for two operands of different types too

Parameters can be passed by value or reference to the operator functions/methods
Operator Overloading

Only existing operators could be overloaded. We can not create new operators of our own
(e.g. **, <>)

Intrinsic properties of overloaded operators can not be changed

Preserves arity (number of operands it takes)

Preserves precedence

Preserves associativity

Both unary prefix and postfix could be oveloaded

void class_name::operator++() // prefix

void class_name::operator++(int) // postfix, int is used to distinguish it from prefix

Like overload of other operators, they can also return value and could be overloaded
using functions

Some operators could not be overloaded

:: . .* sizeof ?:

Operators && || and , could be overloaded but they lose their special properties: short-
circuit evaluation and sequencing (they will not be a sequence point for new types)
#include<iostream> Complex Complex::operator*(int num) {
cout << "Inside method II" << endl;
using std::cout; return Complex(this->re * num, this->im * num);
using std::endl; }

class Complex { // This can not be achieved through operator method


double re, im; Complex operator*(int num, Complex c1) {
public: cout << "Inside friend function" << endl;
Complex(double re = 0, double im = 0) { return Complex(c1.re * num, c1.im * num);
this->re = re; }
this->im = im;
} int main() {
void print() { Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4, c5;
cout << re << " + j" << im << endl; c3 = c1 + c2;
} c4 = c3 * 2;
Complex operator+(Complex &c) { c5 = 2 * c4;
cout << "Inside method I" << endl; c3.print();
// No need of result object c4.print();
return Complex(this->re + c.re, this->im + c.im); c5.print();
} return 0;
Inside method I
Complex operator*(int num); }
Inside method II
friend Complex operator*(int, Complex);
Inside friend function
};
3.3 + j3.3
6.6 + j6.6
13.2 + j13.2
#include<iostream> Complex Complex::operator*(int num) {
cout << "Inside method II" << endl;
using std::cout; return Complex(this->re * num, this->im * num);
using std::endl; }

class Complex { // This can not be achieved through operator method


double re, im; Complex operator*(int num, Complex c1) {
public: cout << "Inside friend function" << endl;
Complex(double re = 0, double im = 0) { return Complex(c1.re * num, c1.im * num);
this->re = re; }
this->im = im;
} int main() {
void print() { Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4, c5;
cout << re << " + j" << im << endl; c3 = c1.operator+(c2); // c1 + c2
} c4 = c3.operator*(2); // c3 * 2
Complex operator+(Complex &c) { c5 = operator*(2, c4); // 2 * c4
cout << "Inside method I" << endl; c3.print();
// No need of result object c4.print();
return Complex(this->re + c.re, this->im + c.im); c5.print();
} return 0;
Inside method I
Complex operator*(int num); }
Inside method II
friend Complex operator*(int, Complex);
Inside friend function
};
3.3 + j3.3
6.6 + j6.6
13.2 + j13.2
#include<iostream> Complex Complex::operator*(int num) {
cout << "Inside method II" << endl;
using std::cout; return Complex(this->re * num, this->im * num);
using std::endl; }
// This can not be achieved through operator method
class Complex { Complex operator*(int num, Complex c1) {
double re, im; cout << "Inside friend function" << endl;
public: return Complex(c1.re * num, c1.im * num);
Complex(double re = 0, double im = 0) { }
this->re = re; int main() {
this->im = im; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4, c5;
} // error: cannot bind non-const lvalue
void print() { // reference of type ‘Complex&’ to an rvalue
cout << re << " + j" << im << endl; // of type ‘Complex’
} // Temporary object can not be assigne to
Complex operator+(Complex &c) { // non-const ref
cout << "Inside method I" << endl; c3 = c1 + c2 * 2;
// No need of result object // No error here as temporary object can
return Complex(this->re + c.re, this->im + c.im); // call method
} c4 = (c1 + c2) * 2;
Complex operator*(int num); c5 = 2 * c1 * 3;
friend Complex operator*(int, Complex); c3.print();
}; c4.print();
c5.print();
return 0;
}
#include<iostream> Complex Complex::operator*(int num) {
cout << "Inside method II" << endl;
using std::cout; return Complex(this->re * num, this->im * num);
using std::endl; }
// This can not be achieved through operator method
class Complex { Complex operator*(int num, Complex c1) {
double re, im; cout << "Inside friend function" << endl;
public: return Complex(c1.re * num, c1.im * num);
Complex(double re = 0, double im = 0) { }
this->re = re; int main() {
this->im = im; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4, c5;
} // error: cannot bind non-const lvalue
void print() { // reference of type ‘Complex&’ to an rvalue
cout << re << " + j" << im << endl; // of type ‘Complex’
} // Temporary object can not be assigne to
Complex operator+(Complex &c) { // non-const ref
cout << "Inside method I" << endl; // c3 = c1 + c2 * 2;
// No need of result object // No error here as temporary object can
return Complex(this->re + c.re, this->im + c.im); // call method
} c4 = (c1 + c2) * 2; Inside method I
Complex operator*(int num); c5 = 2 * c1 * 3; Inside method II
friend Complex operator*(int, Complex); c3.print(); Inside friend function
}; c4.print(); Inside method II
c5.print(); 0 + j0
return 0; 6.6 + j6.6
} 6.6 + j6.6
#include<iostream> Complex Complex::operator*(int num) {
cout << "Inside method II" << endl;
using std::cout; return Complex(this->re * num, this->im * num);
using std::endl; }
// This can not be achieved through operator method
class Complex { Complex operator*(int num, Complex c1) {
double re, im; cout << "Inside friend function" << endl;
public: return Complex(c1.re * num, c1.im * num);
Complex(double re = 0, double im = 0) { }
this->re = re; int main() {
this->im = im; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4, c5;
} // No error, as operator+ accepts arg by value
void print() { c3 = c1 + c2 * 2;
cout << re << " + j" << im << endl; c4 = (c1 + c2) * 2;
} c5 = 2 * c1 * 3;
Complex operator+(Complex c) { c3.print();
cout << "Inside method I" << endl; c4.print(); Inside method II
// No need of result object c5.print(); Inside method I
return Complex(this->re + c.re, this->im + c.im); return 0; Inside method I
} } Inside method II
Complex operator*(int num); Inside friend function
friend Complex operator*(int, Complex); Inside method II
}; 5.5 + j5.5
6.6 + j6.6
6.6 + j6.6
#include<iostream> Complex Complex::operator*(int num) {
cout << "Inside method II" << endl;
using std::cout; return Complex(this->re * num, this->im * num);
using std::endl; }
// This can not be achieved through operator method
class Complex { Complex operator*(int num, Complex c1) {
double re, im; cout << "Inside friend function" << endl;
public: return Complex(c1.re * num, c1.im * num);
Complex(double re = 0, double im = 0) { }
this->re = re; int main() {
this->im = im; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4, c5;
} // No error, as operator+ accepts arg by
void print() { // ref to const
cout << re << " + j" << im << endl; c3 = c1 + c2 * 2;
} c4 = (c1 + c2) * 2;
Complex operator+(const Complex &c) { c5 = 2 * c1 * 3;
cout << "Inside method I" << endl; c3.print(); Inside method II
// No need of result object c4.print(); Inside method I
return Complex(this->re + c.re, this->im + c.im); c5.print(); Inside method I
} return 0; Inside method II
Complex operator*(int num); } Inside friend function
friend Complex operator*(int, Complex); Inside method II
}; 5.5 + j5.5
6.6 + j6.6
6.6 + j6.6
#include<iostream> Complex Complex::operator*(int num) {
cout << "Inside method II" << endl;
using std::cout; return Complex(this->re * num, this->im * num);
using std::endl; }
// Its good practice to pass objects by ref to const
class Complex { Complex operator*(int num, const Complex &c1) {
double re, im; cout << "Inside friend function" << endl;
public: return Complex(c1.re * num, c1.im * num);
Complex(double re = 0, double im = 0) { }
this->re = re; int main() {
this->im = im; Complex c1(1.1, 1.1), c2(2.2, 2.2), c3, c4, c5;
} // No error, as operator+ accepts arg by
void print() { // ref to const
cout << re << " + j" << im << endl; c3 = c1 + c2 * 2;
} c4 = (c1 + c2) * 2;
Complex operator+(const Complex &c) { c5 = 2 * c1 * 3;
cout << "Inside method I" << endl; c3.print(); Inside method II
// No need of result object c4.print(); Inside method I
return Complex(this->re + c.re, this->im + c.im); c5.print(); Inside method I
} return 0; Inside method II
Complex operator*(int num); } Inside friend function
friend Complex operator*(int, const Complex &); Inside method II
}; 5.5 + j5.5
6.6 + j6.6
6.6 + j6.6
#include<iostream> int main() {
Number n1(10), n2(20);
using std::cout; (++++n1).print();
using std::endl; n1.print();
n2++++.print();
class Number { n2.print();
int num; return 0;
public: }
Number(int num) {
this->num = num;
}
Number operator++() {
cout << "Pre-increment:" << num << endl;
num++;
return *this;
}
Number operator++(int) { Pre-increment:10
cout << "Post-increment:" << num << endl; Pre-increment:11
Number temp(*this); 12
num++; 11
return temp; Post-increment:20
} Post-increment:20
void print() { 20
cout << num << endl; 21
}
};
#include<iostream> int main() {
Number n1(10);
using std::cout; cout << "n1 address: " << &n1 << endl;
using std::endl; n1 = ++++n1;
n1.print();
class Number { return 0;
int num; }
public:
Number(int num) {
this->num = num;
}
Number operator++() {
cout << "Pre-increment: " << this << ": ";
cout << num << endl;
num++;
return *this;
}
void print() {
cout << "print function: " << this << ": ";
cout << num << endl;
} n1 address: 0x7fff40a75210
}; Pre-increment: 0x7fff40a75210: 10
Pre-increment: 0x7fff40a75214: 11
print function: 0x7fff40a75210: 12
#include<iostream> int main() {
Number n1(10);
using std::cout; cout << "n1 address: " << &n1 << endl;
using std::endl; ++++n1;
n1.print();
class Number { return 0;
int num; }
public:
Number(int num) {
this->num = num;
}
Number &operator++() {
cout << "Pre-increment: " << this << ": ";
cout << num << endl;
num++;
return *this;
}
void print() {
cout << "print function: " << this << ": ";
cout << num << endl;
} n1 address: 0x7fff92af33d4
}; Pre-increment: 0x7fff92af33d4: 10
Pre-increment: 0x7fff92af33d4: 11
print function: 0x7fff92af33d4: 12
Interesting reads

Operator Overloading

https://en.cppreference.com/w/cpp/language/operators

Why operator function for = operator should return reference of compatible
type

https://stackoverflow.com/questions/42335200/assignment-operator-
overloading-returning-void-versus-returning-reference-param

Why binding temporary object to local non-const lvalue reference is not
allowed while calling of non-const member function by temporary object is
allowed

https://stackoverflow.com/questions/51338287/c-whats-the-design-
philosophy-of-allowing-temporary-object-to-call-non-const

You might also like