You are on page 1of 24

C++

Operator Overloading

Source: How to C++ by


Deitel & Deitel

More notes available at:


http://cplusplus-naturally.blogspot.com/
Introduction
• Operator overloading is the process of enabling existing
C++’s operators to work with class objects.
 Contributes to C++’s extensibility

• Examples:
– << bitwise left-shift operator and stream insertion
operator
– >> bitwise right-shift operator and stream extraction
operator
– + & -  overloaded to perform differently depending on
their context in integer, floating-point arithmetic and
pointer arithmetic

• In C++, most operators can be overloaded to be


sensitive to the context in which they are used. The
compiler generates the appropriate code based on the
manner in which the operator is used.Compiler can
distinguish between overloaded functions by looking at
the data type of their arguments.

• Operator overloading has clearer notion than


corresponding explicit functions calls

• Avoid excessive or inconsistent use of operator


overloading as this can make program cryptic and
difficult to program  Use when usage is obvious –
similar meaning & same syntax.
Introduction – Contd…
• C++ is type-focus and type-sensitive. It is operator rich
language – built-in & those defined to work with user-
defined classes.

• Prototype:
Return type operator<operator-to-be-overloaded>(parameter
list)
{ …}

type  if not ‘void’ then


– Create a temp object (if object to be returned) to use as
return value.
– Use nameless initialized temp object (return
counter(count))
– Return original object using ‘this’

• To use an operator on class objects, that operator must


be overloaded – with two exceptions

• Operators ‘=‘ and ‘&’ can be used with any class without
explicit overloading. The default behaviour of ‘=‘ is
member-wise assignment and ‘&’ is used to return
address of the object in memory.
Introduction Contd…
• Overloading is most appropriate for mathematical
classes. These often require that a substantial set of
operators be overloaded to ensure consistency with the
way these mathematical classes are handled in the real
world. For e.g. a complex number class must have
other operators besides addition.

• Choice of operator overloading depends on meaning &


context of each operator.

• Operator overloading functions can be – member


functions, friend functions & rarely, non-member non-
friend functions

• Overload operators to perform the same function or


similar functions on the class objects as the operators
perform on objects of built-in types.  Avoid non-
intuitive use of operators

• Before overloading consult the manuals for compiler


restrictions & requirements unique to particular objects.
Restrictions On Operator Overloading
• Following operators cannot be overloaded:
– .*
– ::
– ?:
– Sizeof

• Attempting to overload a non-overloadable operator is


syntax error.

• Operator overloading cannot change operator’s:


– Precedence: However, order of evaluation can be
changed using paranthesis
– Associativity
– Arity: Operators (&,*,+,-) have unary & binary versions;
thse can be overloaded separately.

• It is not possible to create new operators; only existing


operators can be overloaded. Attempting to do so is a
syntax error. Therefore, ** can be overloaded for
exponentiation.

• Attempting to modify how an operator works with


objects of built-in types is a syntax error.

• Binary operator cannot be overloaded to be unary


Restrictions On Operator Overloading …
• Operator overloading works only with objects of user-
defined types or with a mixture of an object of a user-
defined type and an object of a built-in type.

• Atleast one argument of an operator function must ne


class object or a reference to a class object. This
prevents programmers from chnaging how operators
work on built-in types

• Assuming that overloading an operator such as ‘+’


overloads related operators such as ‘+=‘ or that
overloading ‘==‘ overloads ‘!=‘ is error. Operators can
be overloaded only explicitly, there is no implicit
overloading

• To ensure consistency among related operators, use


one to implement the others (ie use an overloaded ‘+’
operator to implement an overloaded ‘+=‘ operator).
Operator Functions as Class Members Vs
Friend Functions
• Non member functions are made friends for
performance reasons.

• In case of binary operators, member functions use ‘this’


pointer implicitly to obtain one of their class object
arguments (the left argument for binary operator)

• In case of non-member functions, both class arguments


must be explicitly listed in call

• When overloading (), [], , or any assignment


operators, the operator overloading function must be
declared as class member.

• For other operator, the operator overloading functions


can be non-member functions

• When an operator function is implemented as a


member function (the leftmost (or only) operand must
be a class (or a reference to a class object) of the
operators’ class
Operator Functions as Class Members Vs
Friend Functions …
• If the left operand must be an object of a different class or
built-in type, this operator function must be implemented as a
non-member function. For e.g. ‘<<‘ or ‘>>’

• A non-member operator function needs to be friend if that


function must access private or protected members of that
class directly

• If non-member functions used for operator overloading are not


friend functions then set/get functions may be used. The
overhead of calling these functions could cause poor
performance, so these functions can be inlined to improve
performance.

• Operator member functions of a specific class are called only


when the left operand of a binary operator is specifically an
object of that class, or when the angle operand of a unary
operator is an object of that class

• Use non-member operator overloading function to enable the


operator to be commutative. For e.g. if we overload ‘+’ as
member function ten for using it with ‘long int class object
Huge integer Object’, left operand must be object of that
class. So, to make it commutative, overload the operator as a
non-member friend function to allow HugeInteger to appear on
the right of the addition.
Overloading Stream Insertion &
Stream Extraction Operator
• These operators are overloaded (in class libraries
provided with C++ compilers) to process each built-in
data type including C-like char* string & Pointers

• They can also be overloaded to perform i/o operations


for user defined types

• E.g. of overloading >> & << for PhoneNumber class

• // Why not member function

• These operators must be non-members because object


of class appears in each case as the right operand
must appear on the left of the operator to overload that
operator as a member function.
Overloading Unary Operators
• A unary operator for a class can be overloaded as a
non-static member function with no arguments or as a
non-member function with one argument; that argument
must be either an object of the class or a reference to
an object of the class.

• Non-static so that they can access non-static data


members because static member functions can only
access static data members of the class

• E.g. overloading ! Operator for class string to check if


empty & return a bool result

• Case 1: Non-static member function with no arguments


– !s is converted into s.operator!() is invoked
Class string {
public:
bool operator !() const;
….
};

– Operator is used on the object of which it is a member


Overloading Unary Operators …
• Case 2:Non-member function with one argument
(Object copy / Object reference)
!s  operator!(s)
class string{
friend bool operator(const string &)

};

• When overloading unary operator it is preferable to


make the operator function class member instead of
non-member friend function.

• Friend function and friend classes must be avoided


unless they are absolutely necessary. The friend usage
violates the use of encapsulation of a class.
Overloading Binary Operators
• The argument on the LHS of operator is the object of
which operator is a member function. The object on the
RHS must be furnished as an argument to operator.
Returned value may be assigned or used in any other
ways.  Overloaded operator always require on less
argument than its number of operands.

• Overloading as non-static member function with one


argument
y+=z operator+=(z)
const string &operator +=(const string &);

• Non-member function with two arguments (one of them


needs to be either a class object or a reference to a
class object)
y+=z operator+=(y, z)
friend const string &operator +=(string &, const string &);
Case Study: An Array Class
• Arrays in C++ just an alternative to pointers  so,
arrays have much potential for errors.

• For arrays, C++ does not provide such capabilities like


– Subscript range checking
– Two arrays comparison with equality/relational operators
– When an array is passed to a general purpose function
designed to handle arrays of any size, the size of the
array must be passed as an additional argument.
– One array cannot be assigned to another with assignment
operator (s) (because array names are const pointers & a
const pointer cannot be used on LHS of assignment
operator.

• But C++ does provide means to implement these


capabilities through the mechanisms of operator
overloading.

• //array example

• Subscript operator [] can be used to select elements


from container classes like linked lists, strings,
dictionaries etc. Also, subscripts no longer have to be
integer; they can be characters, strings, floats or even
objects of user-defined classes
Case Study: An Array Class …
• Copy constructor must use call-by-reference not call-
by-value. Otherwise, the copy constructor call results in
infinite recursion (a fatal logical error) because for call-
by-value a copy of the object passed to the copy
constructor must be made, which results in copy
constructor being called recursively. A copy constructor
is used to initialize an object with another object of
same class…(to be completed from chapter highlights)

• If the copy constructor simply copied the pointer in the


source object to the target object’s pointer, then both
objects would point to the same dynamically allocated
storage. The first destructor to execute would then
delete the dynamically allocated storage & the other
object’s pointer would then be undefined, a situation
called a “dangling pointer” & likely to result in serious
run-time error.

• A constructor, a destructor, an overloaded assignment


operator and a copy constructor usually provided as a
group of any class that uses dynamically allocated
memory. Not providing an overloaded assignment
operator and a copy constructor for such a class is a
syntax error.
Case Study: An Array Class …
• Declaring assignment operator as private prevents one
class object being assigned to another.

• Making overloaded assignment operator & copy


constructor private prevents class objects from being
copied

• Self assignment of objects is dangerous because …

• Multiple Overloading: If in same program with multiple


classes having same operator being overloaded then
C++ can select correct function to carry out “addition”
based on type of operand.
Converting between Types
• Conversion is required in assignments, in calculations,
in passing values to functions & in returning values from
functions.

• Compilers know how to perform certain conversions


among built-in types. This implicit conversion is done
through built-in routines. Can also convert if user-
defined objects are same on both sides.

• For conversion among user-defined types & built-in


types, conversion constructors are needed – single
argument constructor that turn objects of other types
(including built-in types) into objects of a particular
(constructor’s) class. This constructor is called implicitly
by the constructor.

• A constructor/cast operator converts an object of one


class into an object of another class or into an object of
a built-in type. //Assignment operator or overloaded role
from CHHG

• This operator must be a non-static member function

• It cannot be a friend function

• It does not specify a return type – type to which an


object is being converted

• Prototype for cast operator: CastFromClass::operator


const
Converting between Types …
• Prototype for cast operator: CastFromClass::operator
const

– E.g. A::operator char *() const; (char *)s=s.operator


char*()

• When necessary, the compiler can call cast operators


and conversion constructors to create temporary
objects
– E.g. for object ‘s’ of class string, cout << s is
converted by compiler to first (char *) as required by
cout  so for class string << need not be
overloaded for cout

• For converting a basic type into user-defined type, one


argument constructor is used.
• Complier blurs distinction between definition &
assignment. If no overloaded operator available then
compiler will look for the constructor to do the same job.
Distance d1 = 2.345;
d1 = 1.0;  Constructor is used but no
new object is created (through unnamed object)
• For converting a user-defined type to basic, a
conversion function is required
– Mtrs=float(dist2) and mtrs = dist2 will use same
conversion function
Converting between Types …
• For converting from user-define to another user-defined
type then if conversion routine to be in source object,
use conversion function else (conversion routine to be
in destination object) use one-argument constructor.
• In second case, special functions (get functions) may
be required to provide access to private data members
of object to be converted

 Avoid doing same conversion in more than one way i.e.


single argument constructor is destination object &
conversion function in source object.
Overloading ++ and --
• These operators have both prefix and postfix versions.

• So, each operator overloading function must have a


distinct signature so the compiler will be able to
determine which versions of ++/-- is intended

• Prefix versions are overloaded exactly as any other


prefix unary operator would be.

• Postfix versions are overloaded in a manner to have


different signature, achieved by making argument list
for postfix version.

• Example declarations:
Date d1;
Pre-incrementing
Member function:
++d1 = d1.operator(); Prototype Date operator ++()
Non-member function:
++d1 = operator(d1); Prototypefriend Date operator++(Date
&)
Post-incrementing
Member function:
d1++ = d1.operator(0); Prototype Date operator ++(int)
Non-member function:
d1 ++= d1.operator(d1,0); Prototypefriend Date
operator++(Date &,int)
Overloading ++ and -- …
• Similar is the case for pre-and post decrementing

 It is not an argument but a signal to compiler to


use postfix notation.

c2 = c1++;  c1 is first assigned to c2 and then


incremented
Operators that cannot be overloaded
• Member access dot operator (.)
• Scope resolution (::)
• Conditional Operator (?:)
• Pointer to member (.*)
• sizeof()
Some uses of operator overlaoding
• Add English distances: Add X1 to X2 & Y1 to
Y2
• Add Polar Co-ordinates: 3 step approach 
convert to English, Add, Convert back
• String Concatenation: Check final string should
not result in overflow
• Distance & String comparison
• Polar to rectangular conversion
More notes available at:

• http://www.cplusplus-naturally.blog

• http://zainvi.sf.googlepages.com/in

• http://www.computer-science-note
u 
Y o
an k
T h
n s ?
s t i o s ?
u e t io n
Q e s
g g
Su

You might also like