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); Prototypefriend Date operator++(Date
&)
Post-incrementing
Member function:
d1++ = d1.operator(0); Prototype Date operator ++(int)
Non-member function:
d1 ++= d1.operator(d1,0); Prototypefriend 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