Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
5 views20 pages

Lab 10

The document covers operator overloading in C++ and Python, detailing member vs non-member functions, returning objects vs references, and class conversion methods. It explains the syntax for operator functions, the implications of returning objects versus references, and the use of implicit and explicit conversions. Additionally, it provides examples and exercises to reinforce understanding of the concepts presented.

Uploaded by

miaowuxvxv
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)
5 views20 pages

Lab 10

The document covers operator overloading in C++ and Python, detailing member vs non-member functions, returning objects vs references, and class conversion methods. It explains the syntax for operator functions, the implications of returning objects versus references, and the use of implicit and explicit conversions. Additionally, it provides examples and exercises to reinforce understanding of the concepts presented.

Uploaded by

miaowuxvxv
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/ 20

Advanced Programming

Lab 10, Class(2): operator overloading

廖琪梅,王大兴, 于仕琪,王薇

1
Topic
• Operator overloading in C++
• Member function vs Non-member function( e.g. Friend function)
• Returning object vs Returning reference
• Conversion of class
• implicit conversion vs explicit conversion
• conversion function

• ‘Operateor overloading’ in Python


• x + y : type(x).__add__(x, y)
• x + y: type(y).__radd__(y, x)
• __str__()

• Exercises

2
Operator overloading in C++

3
Operator overloading
To overload an operator, use a special function form called an operator function.

return_type operator op(argument-list)

op is the symbol for the operator being overloaded

An operator function must either be a member function of a class or have at


least one parameter of class type.

4
member function, non-member function, friend function

Non-member operator overloads are required to enable type conversion on the


left operand. If a function needs such conversion, define it as a non-member. If it
also requires access to non-public members, declare it as a friend of the class.

Other cases beyond the above, define the function as a member function.

The assignment (=)operators must be defined as member functions. However,


IO operators(<< and >>) must be non-member functions.

5
Returning object
Return the value, or the reference?

1. Returning an object

When a function returns an object, a temporary object will be created. There is


the added expense of calling the copy constructor to create the temporary object,
it is less efficient. It is invisible and does not appear in your source code. The
temporary object is automatically destroyed when the function call terminates.

6
Do not return the reference of a local object, because when the function
terminates, the reference would be a reference to a non-existent object.

7
Returning a reference to this object works efficiently, but it modifies the
values of the data member of this object.

This return style is known as return constructor argument. By using this style instead
of returning an object, the compiler can eliminate the cost of the temporary object.
This even has a name: the return value optimization.
8
2. Returning a reference to an object

• Returning an object invokes the copy constructor, whereas returning a reference doesn’t. Thus
version 2 does less work and is more efficient.
• The reference should be to an object that exists when the calling function is executing.
• Both v1 and v2 are declared as being const references, so the return type has to be const to
match.

Two common examples of returning a non-const object are overloading the assignment operator and
overloading the << operator for use with cout.

9
Conversion of class
1. Implicit Class-Type Conversions
Every constructor that can be called with a single argument defines an implicit conversion to
a class type. Such constructors are sometimes referred to as converting constructors.

Convert int when we use the copy form


to Circle type of initialization or assignment
(with an =), implicit
conversions happens.

Convert int
to Circle type
Converting constructor

10
Convert int to
Rational type
Constructor with default arguments
works as a converting constructor.

We define the operator * as a normal function not a friend 11


function of the Rational class.
Use explicit to supper the implicit conversion
We can prevent the use of a constructor in a context that requires an implicit conversion by
declaring the constructor as explicit:

Can not do the


implicit conversion

Turn off implicit conversion Use these two styles


for explicit conversion

12
2. Conversion function
Conversion function is a member function with the name operator followed by a type
specification, no return type, no arguments.

operator typeName( );

Convert Rational object a to


double by conversion function

Declare a conversion operator as


explicit for calling it explicitly
Caution: You should use
implicit conversion
functions with care.
Often a function that can
only be invoked explicitly
13
conversion function is the best choice.
Operator overloading in Python

14
‘Operateor overloading’ in Python
• In Python, operator overloading is accomplished by implementing special methods of classes (also
known as magic methods). These methods start and end with double underscores (such as __add__).
implement the binary arithmetic operations

object.__add__(self, other)
These methods are called to implement the binary arithmetic
object.__sub__(self, other)
operations (+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |).
object.__mul__(self, other)
object.__matmul__(self, other)
For instance, to evaluate the expression x + y, where x is an
object.__truediv__(self, other)
instance of a class that has an __add__() method,
object.__floordiv__(self, other)
type(x).__add__(x, y) is called.
object.__mod__(self, other)
object.__divmod__(self, other)
object.__pow__(self, other[, modulo])
object.__lshift__(self, other)
object.__rshift__(self, other)
object.__and__(self, other)
object.__xor__(self, other)
object.__or__(self, other)
https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types 15
Implement the binary arithmetic operations with
reflected (swapped) operands
These methods are called to implement the binary arithmetic
object.__radd__(self, other) operations (+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |)
object.__rsub__(self, other) with reflected (swapped) operands.
object.__rmul__(self, other)
object.__rmatmul__(self, other) These functions are only called if the left operand does not
object.__rtruediv__(self, other) support the corresponding operation and the operands are
object.__rfloordiv__(self, other) of different types.
object.__rmod__(self, other)
object.__rdivmod__(self, other) For instance, to evaluate the expression x - y, where y is an
object.__rpow__(self, other[, modulo]) instance of a class that has
object.__rlshift__(self, other) an __rsub__() method, type(y).__rsub__(y, x) is called
object.__rrshift__(self, other)
object.__rand__(self, other) if type(x).__sub__(x, y) returns NotImplemented.
object.__rxor__(self, other)
object.__ror__(self, other)

https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types 16
#include <iostream> //MyTime.cpp
class MyTime{
int hours;
int minutes;
public:
class MyTime: #MyTime.py MyTime(): hours(0), minutes(0){}
def __init__(self, h=0, m=0): MyTime(int h, int m): hours(h), minutes(m){}
MyTime operator+(int m) const{
self.hours=h
MyTime sum;
self.minutes=m
sum.minutes=this->minutes+m;
sum.hours=this->hours;
def __add__(self, other): sum.hours+=sum.minutes/60;
if isinstance(other, int): sum.minutes%=60;
total_min=self.minutes+other return sum;
new_hours=self.hours+total_min//60 }
new_minutes=total_min%60 friend MyTimeoperator+(int m, const MyTime&t){
return MyTime(new_hours, new_minutes) return t+m;
return NotImplemented }
friend std::ostream& operator<<(std::ostream&os, const MyTime&t){
def __radd__(self, other): std::string str=std::to_string(t.hours) +" hours and "
return self.__add__(other) +std::to_string(t.minutes) +" minutes.";
os<<str;
return os;
def __str__(self):
}
return f"{self.hours} hours and {self.minutes}
};
minutes."
int main(){
MyTime mt(1,59);
if__name__=="__main__": std::cout<<mt+2<<std::endl;
mt=MyTime(1, 59) std::cout<<1+mt<<std::endl;
print(mt+2) return 0;
print(1+mt) }
17
Exercise1
Modify the code(rational.h) so that the program runs as shown in the screenshot on the right and explain
the output where each constructor is run.

// rational.h
#pragma once
#include <iostream>
class Rational{
private: #include <iostream>
staticint id; #include "rational.h"
int numerator; using namespace std;
int denominator; int main(){
public: Rational a=10;
Rational(int n=0, int d=1): numerator(n), denominator(d){ Rational b(1,2);
std::cout<<"Construct_"<<id<<", n:"<<numerator<<" , Rational c=a*b;
d:"<<denominator<<std::endl; cout<<"c = "<<c<<endl;
} Rational d=2*a;
cout<<"d = "<<d<<endl;
int getN() const { return numerator; } Rational e=b*3;
int getD() const { return denominator; } cout<<"e = "<<e<<endl;
friend std::ostream & operator<<(std::ostream& os, const Rational&rhs){ Rational f=2*3;
os<<rhs.numerator<<"/"<<rhs.denominator; cout<<"f = "<<f<<endl;
returnos; return0;
} }
};
int Rational::id=0;
const Rational operator*(constRational&lhs, const Rational&rhs){
return Rational(lhs.getN()*rhs.getN(), lhs.getD()*rhs.getD() );
}

18
Exercise2
Please modify the code(rational.h) in Exercise1 to the program runs as shown in the screenshot.
Explain what modifications have been made and wy.

// rational.h
#pragma once
#include <iostream>
class Rational{
private: #include <iostream>
staticint id; #include "rational.h"
int numerator; using namespace std;
int denominator; int main(){
public: Rational a=10;
Rational(int n=0, int d=1): numerator(n), denominator(d){ Rational b(1,2);
std::cout<<"Construct_"<<id<<", n:"<<numerator<<" , Rational c=a*b;
d:"<<denominator<<std::endl; cout<<"c = "<<c<<endl;
} Rational d=2*a;
cout<<"d = "<<d<<endl;
int getN() const { return numerator; } Rational e=b*3;
int getD() const { return denominator; } cout<<"e = "<<e<<endl;
friend std::ostream & operator<<(std::ostream& os, const Rational&rhs){ Rational f=2*3;
os<<rhs.numerator<<"/"<<rhs.denominator; cout<<"f = "<<f<<endl;
returnos; return0;
} }
};
int Rational::id=0;
const Rational operator*(constRational&lhs, const Rational&rhs){
return Rational(lhs.getN()*rhs.getN(), lhs.getD()*rhs.getD() );
}

19
Exercise3
Continue to improve the Complex class and add more operations for it, such as: -,
*, ~, ==, != etc. Make the following program run correctly.

Note that you have to overload the <<


and >> operators. Use the references to
objects and const whenever warranted.
The sample should run as follows:

20

You might also like