Title: Operator Overloading
1SECTION 8
2Operator Overloading
- Overloading refers to the multiple meanings of
the same name or symbol. - Name overloading
overloaded function. - Symbol overloading
overloaded operator.
3Operator Overloading
- An operator is a symbol that is used to represent
specific operations on its operand(s). - e.g.
- arithmetic operator , -, , /
- logical operator and
- pointer operator and
- memory management operator new, delete
- A binary operator is an operator that takes two
operands a unary operator is one that takes one
operand.
4Operator Overloading
- An operator can be viewed as a function name.
- Examples
- x y (x, y)
- x (x)
- Operators are an example of syntactic sugar,
which refers to a slightly different but more
user-friendly syntax.
5Operator Overloading
- Arithmetic operator such as and / are already
overloaded in C/C for different built-in types. - For example, the same operator / , different
algorithms are used to compute two types of
divisions. - 2 / 3 // integer division result
is 0 - 2.0 / 3.0 // floating-point division
result is 0.666667
6Operator Overloading
- C allows most operators to be overloaded for
user-defined types (classes). - The following operators can be overloaded
- new new delete delete
- - /
- ! lt gt
- - /
- gtgt ltlt ltlt gtgt ! lt
- gt -- , -gt
- -gt ()
7Operator Overloading
- The following can not be overloaded
- . . ? sizeof typeid
8Why operator overloading?
- Overloaded operators have the appropriate meaning
to user-defined types, therefore they can be used
for these types just like they are used for
built-in types.
9Why operator overloading?
- Example 1 use operator for adding two objects
of user-defined type complex number. - include "complex_number.h"
- complex_number x(1, 2), y(2, 3)
- cout ltlt ( x y )
- Example 2 compare two date objects by chronology
of the year. - include "date.h"
- Date(6, 4, 1989) lt Date(8, 15, 1999)
- Date(4, 1, 2002) Date("4/1/2002")
10Why operator overloading?
- An operator must be overloaded to be used on
class objects, but with two exceptions operator
and operator - Operator and operator are overloaded
implicitly for every class. - operator performs member-wise copy of the data
members. - operator returns the address of the object in
memory.
11- Example
- class Myclass
- public
- Myclass() x(0), y(0)
- Myclass(int xx, int yy) x(xx), y(yy)
- private
- int x, y
-
- int main()
- Myclass c1, c2(5,6)
- Myclass ptr
- c1 c2 // use overloaded
operator - ptr c2 // use overloaded
operator
12How to overload operators?
- We can overload operators by writing special
kinds of functions. These functions are called
operator function. - To overload operator _at_, the name of the operator
function is operator_at_ - These operator functions can be
- class member function, or
- stand-alone function.
13Overload Operator as Class Member
- Consider a binary operator _at_ xobj is an object
of class X and yobj is of Y. - In order to use this operator _at_ as the following
- xobj _at_ yobj
- we define a member function operator_at_ in class X.
14Overload Operator as Class Member
- Overloading operator
- To overload operator for class Myclass so that
we can add two Myclass objects with the result
being another Myclass object. - We declare a method named operator in class
Myclass.
15- class Myclass
- public
- Myclass operator( Myclass )
- // constructors
- Myclass() x(0), y(0)
- Myclass(int xx, int yy) x(xx), y(yy)
- private
- int x, y
-
- // the operator member function
- Myclass Myclassoperator( Myclass m )
- return Myclass ( x m.x, y m.y )
16Overload Operator as Class Member
- Now, we can invoke operator, just like a regular
class member function. - Myclass a, b
- a.operator( b )
- Since the keyword operator, this member function
can also be invoked as - a b
- Here, we add the Myclass objects a and b to
obtain another Myclass object.
17- Example A complex number class.
- A complex number is a number of the form z a
bi. where i represents the square root of -1 a
is the real part of z and b is the imaginary part
of z. - Arithmetic operations on complex numbers are
defined as follows - (a bi) (c di) (a c) (b d)i
- (a bi) - (c di) (a - c) (b - d)i
- (a bi) (c di) (ac bd) (ad bc)i
- (a bi)/ (c di) (ac bd)/(c2 d2) ((bc -
ad)/(c2 d2))i - Implement a class that represents complex
numbers, overloads ,-, , / to support complex
arithmetic and overloads equal ( ) and not
equal (!) operator to support complex number
comparison.
18- include ltiostreamgt (sam1.cpp)
- using namespace std
- class Complex
- public
- Complex()
- Complex( double )
- Complex( double, double )
- void print() const
- Complex operator( const Complex ) const
- Complex operator-( const Complex ) const
- Complex operator( const Complex ) const
- Complex operator/( const Complex ) const
- bool operator( const Complex ) const
- bool operator!( const Complex ) const
- private
- double real
- double imag
19- ComplexComplex()
- real imag 0.0
-
- ComplexComplex( double re )
- real re
- imag 0.0
-
- ComplexComplex( double re, double im )
- real re
- imag im
-
- void Complexprint() const
- cout ltlt real ltlt " " ltlt imag ltlt "i\n"
20- Complex Complexoperator( const Complex u )
const - Complex v( real u.real,
- imag u.imag )
- return v
-
- Complex Complexoperator-( const Complex u )
const - Complex v( real - u.real,
- imag - u.imag )
- return v
-
- Complex Complexoperator( const Complex u )
const - Complex v( real u.real - imag u.imag,
- imag u.real real u.imag )
- return v
21- Complex Complexoperator/( const Complex u )
const - double abs_sq real u.real imag u.imag
- Complex v( ( real u.real imag u.imag ) /
abs_sq, - ( imag u.real - real u.imag ) / abs_sq )
- return v
-
- bool Complexoperator( const Complex u )
const - return (real u.real imag u.imag)
-
- bool Complexoperator!( const Complex u )
const - return !(real u.real imag u.imag)
22- A simple test client
- int main()
- Complex c1( 8.8, 0 )
- Complex c2( 3.1, -4.3 )
- Complex c3 c1 c2
- Complex c4 c2 - c1
- c3.print()
- c4.print()
- if ( c3 c4 )
- cout ltlt "No way!"
- else
- cout ltlt "You got it."
23Overloading operator
- Operator is used to copy each data member from
the source object to the corresponding data
member in the target object. - If user does not overload operator for a class.
The compiler provides a default overloaded
version that does the member-wise copying. - The default version is dangerous for classes
whose data members include a pointer to
dynamically allocated memory. - Note The situation here is similar to classs
copy constructor.
24- Example (sam2.cpp)
- class Vector
- public
- Vector( int n )
- Vector()
- // ...
- private
- int size
- int ptr
-
- VectorVector(int n)
- size n
- ptr new intsize
- for ( int i0 iltsize i)
- ptri 0
25- VectorVector()
- delete ptr
-
- int main()
- Vector a(10)
-
- Vector b(10)
- //...
- b a
-
- Vector c a // !?
-
- Memberwise copy is dangerous.
26- Solution
- // overload for class Vector
- class Vector
- // ...
- Vector operator( const Vector )
//end of class definition - Vector Vectoroperator( const Vector v )
- if (this ! v) // not assigning to myself
- size v.size
- delete ptr
- if ( v.ptr ! 0 ) // not empty
- ptr new intsize // allocate new memory
- for ( int i0 iltsize i )
- ptri v.ptri
-
- else // empty
- ptr 0
-
- return this
27Overloading operator
- Note write the copy constructor, the overloaded
assignment operator and destructor for classes
with pointers referring to dynamically allocated
memory(The Big Three principal )
28Binary v.s. Unary operator
- If we use a class member function to overload a
binary operator, the member function has only one
parameter. - Similarly, if we use a class member function to
overload a unary operator, the member function
has no parameters.
29- Example Overloading unary operator !
- class Myclass
- public
- Myclass operator!() // takes no argument
- // ...
- private
- int x, y
-
- Myclass Myclassoperator!()
- Myclass tmp( -x, -y )
- return tmp
-
- ...
30Overloading the Increment andDecrement operators
- The operator and -- have two forms pre and
post - int x 6
- x // preincrement
- x // postincrement
- --x // predecrement
- x-- // postdecrement
- To overload the preincrement and predecrement
operator, we use the declaration - operator()
- operator--()
31Overloading the Increment andDecrement operators
- To overload the postincrement and postdecrement
operator, we include a dummy int parameter in the
declaration - operator( int )
- operator--( int )
- The int is used to distinguish the post from the
pre form.
32- Example (sam3.cpp)
- include ltiostreamgt
- using namespace std
- class Myclass
- public
- void print()
- Myclass operator( )
- Myclass operator(int)
- Myclass() x(0), y(0)
- Myclass(int xx, int yy) x(xx), y(yy)
- private
- int x, y
-
- void Myclassprint()
- cout ltlt "x " ltlt x ltlt "y " ltlt y ltlt "\n"
33- Myclass Myclassoperator() // preincrement
- x
- y
- return this
-
- Myclass Myclassoperator(int n) //
postincrement - Myclass tmp this
- x
- y
- return tmp
34- A simple test client
- int main()
- Myclass a(1,1), b(1, 1), c
- c a
- a.print()
- c.print() // x 1 y 1
- c b
- b.print()
- c.print() // x 2 y 2
35Overload Operator as Stand-alone Function
- Consider a binary operator _at_ xobj is an object
of class X and yobj is of Y. - To use _at_ as xobj _at_ yobj
- we can overload operator_at_ as a stand-alone
function which takes two parameters one of type
X and one of type Y. - operator_at_ ( X, Y )
36Overload Operator as Stand-alone Function
- Example
- To overload operator using a stand-alone
function, we define the following - Myclass operator( Myclass x, Myclass y)
- // ...
-
- This stand-alone function operator, has two
parameters - the two Myclass objects, and returns
one Myclass object.
37Overload Operator as Stand-alone Function
- Following the usual syntax for invoking a
function, the operator can be invoked as - Myclass x, y, z
- z operator( x , y )
- Since the keyword operator, this function can be
invoked as - z x y
38- Consider the following implementation for
overloading using stand-alone function is there
a problem? - class Myclass
- public
- void print()
- Myclass() x(0), y(0)
- Myclass(int xx, int yy) x(xx), y(yy)
- private
- int x, y
-
- // overload operator as stand-alone function
- Myclass operator( Myclass c1, Myclass c2 )
- Myclass tmp( c1.x c2.x,
- c1.y c2.y )
- return tmp
39- The operator can not access private data member
of class Myclass.
40- Solution 1 Add accessor member function.
- class Myclass
- public
- int getX() return x
- int getY() return y
- // rest omitted
- private
- int x, y
-
- Myclass operator( Myclass c1, Myclass c2 )
- Myclass tmp( c1.getX() c2.getX(),
- c1.getY() c2.getY() )
- return tmp
41- Solution 2 Use friend functions
- class Myclass
- public
- // rest omitted
- private
- int x, y
- friend Myclass operator( Myclass, Myclass )
-
- // as stand-alone friend
- Myclass operator( Myclass c1, Myclass c2 )
- Myclass tmp( c1.x c2.x,
- c1.y c2.y )
- return tmp
42Operator functionsAs class member v.s. As
stand-alone
- Using class member functions, the overloaded
operator is invoked as a member function on an
object. - a b c
- a b.operator( c )
- Using stand-alone functions, the overloaded
operator is invoked as a function that treats the
two operands equally. - a operator( b , c )
43Operator functionsAs class member v.s. As
stand-alone
- An operator intended to accept a basic type as
its first operand can only be overloaded as stand
alone function.
44Overloading the Input and Outputoperators
- Bitwise operator gtgt ( right shift ) and ltlt ( left
shift ) are built-in operators in C/C. - These two operators are overloaded in system
library for formatted input and output of
built-in types.
45Overloading the Input and Outputoperators
- Example
- In class ostream
- ostream operatorltlt( const char )
- ostream operatorltlt( const int )
- ostream operatorltlt( const char )
- //...
46Overloading the Input and Outputoperators
- Since cout is an object of ostream, the following
code - int i
- char s
- //...
- cout ltlt i
- cout ltlt s
- can be interpreted as
- cout.operatorltlt( i )
- cout.operatorltlt( s )
47Overloading the Input and Outputoperators
- ltlt and gtgt can be further overloaded for
user-defined types. - Question Do we overload ltlt and gtgt as stand-alone
function or class member function?
48- Example
- To overload gtgt to read into a Myclass object as
the following - Myclass c
- cin gtgt c
- we write a stand-alone function operatorgtgt as
- istream operatorgtgt( istream in, Myclass m)
- return ( in gtgt m.x gtgt m.y )
-
- // as friend
49- Thus, the statement
- cin gtgt c
- is now equivalent to
- operatorgtgt( cin, c )
- which is evaluated as
- cin gtgt c.x gtgt c.y
50- Complex number class revisit
- include ltiostreamgt
- using namespace std
- class Complex
- public
- Complex()
- Complex( double )
- Complex( double, double )
- friend Complex operator( const Complex, const
Complex ) - friend Complex operator-( const Complex, const
Complex ) - friend Complex operator( const Complex, const
Complex ) - friend Complex operator/( const Complex, const
Complex ) - friend bool operator( const Complex, const
Complex ) - friend bool operator!( const Complex, const
Complex ) - friend istream operatorgtgt( istream, Complex )
- friend ostream operatorltlt( ostream, const
Complex ) - private
- double real, imag
51- //...
- istream operatorgtgt( istream in, Complex c )
- return in gtgt c.real gtgt c.imag
-
- ostream operatorltlt( ostream out, const Complex
c ) - return out ltlt c.real ltlt " " ltlt c.imag ltlt "i" ltlt
endl -
- int main()
- Complex c1, c2
- cin gtgt c1 gtgt c2
- cout ltlt c1 ltlt c2
- cout ltlt c1 c2
52Overloading Operator
- An overloaded subscript operator must be defined
as class member function. - class Vector
- public
- // ...
- int operator(int)
- private
- int v
- int v_size
-
- int Vectoroperator( int index )
- return vindex
53- //...
- Vector vec(10)
- for( int i0 iltvec.size() i )
- veci veci i
- //same as vec.operator(i)vec.opera
tor(i)i
54Overloading Operator ()
- An overloaded function call operator must be
defined as class member function.
55- Class MyFunction
- // ...
- public
- int operator()(int)
-
- int MyFunctionoperator()(int x)
- return xxx
-
- //...
- MyFunction f
- cout ltlt f(100) //equivalent to
coutltltf.operator() (100) - Here, f is an example of function object, or
functor.
56Rules on operator overloading
- User can not create new operators.
- The precedence of the operator can not be
changed. - The number of operands required by the operator
can not be changed. - Overload operator only when it is necessary.
57Type Conversion
- Implicit Conversions
- Conversions are carried out automatically by the
compiler.
58Type Conversion
- Example
- int f(int)
- // ...
- int i
- double d
- i d // int i converted to double
- d i // int i converted to double
- i d // double d converted to int
- f(d) // double d converted to int
59Type Conversion
- Explicit Conversions(Cast)
- Conversions are specified by the programmer.
- Example
- int i, j
- (double)i / j
60User Defined Conversion
- Conversion to user-defined type Use
constructors to perform an implicit conversion. - Example
- class Complex
- public
- Complex( double )
- Complex( double, double )
- //...
61User Defined Conversion
- void f(Complex)
- double x
- int y
- f(x) // ok
- f(y) // ok
- We can use keyword explicit to disable
user-defined implicit conversion
62User Defined Conversion
- Conversion from user-defined type
- Use conversion functions.
- A conversion function is a special class member
function that defines a conversion to convert a
class object into some other type. - Prototype
- operator NEWTYPE(void)
63- Example
- class Rational
- public
- operator double() //conversion function
- // ...
- private
- long num, den
- // ...
-
- Rationaloperator double()
- return double(num)/den
-
- double x
- Rational r(2, 3)
- x double(r) // ok explicit conversion, same
as r.double() - x r // ok implicit conversion
64- Example A rational number class
- Description
- The rational numbers are the set of quotients P/Q
where P and Q are integers and Q can not be zero.
- The number P is called the numerator and the
number Q is called the denominator.
65- class Rational (sam4.cpp)
- public
- // constructors that handle conversion
- // int -gt rational, double-rational
- Rational( int0, int1 )
- Rational( double )
- // binary and unary operators
- Rational operator (const Rational v) const
- Rational operator- (const Rational v) const
- Rational operator (const Rational v) const
- Rational operator/ (const Rational v) const
- Rational operator- () const
66- // relational operators
- bool operatorlt (const Rational v) const
- bool operatorlt (const Rational v) const
- bool operator (const Rational v) const
- bool operator! (const Rational v) const
- bool operatorgt (const Rational v) const
- bool operatorgt (const Rational v) const
- // conversion operator rational -gt double
- operator double() const
- // rational number input/output
- friend istream operatorgtgt (istream in,
Rational v) - friend ostream operatorltlt (ostream out,
Rational v)
67- // utility methods
- int getNumerator() const return num
- int getDenominator() const return den
- void reduce()
- private
- void standardize() // rational unility methods
- int gcd(int, int)
- long num, den
68- //approximate double x to a rational number
- RationalRational(double x)
- double val1, val2
- // move decimal part of x 8 pos to the right
- val1 100000000L x
- // move deciaml part of x 7 pos to the right
- val2 10000000L x
- // get rid of the fractional part approx x
- num long(val1-val2)
- den 90000000L
- reduce()
69- RationalRational(int x, int y) num(x),
den(y) - if ( den0)
- cerr ltlt "Error zero denominator \n"
- exit(1)
-
- reduce()
-
- Rational Rationaloperator (const Rational v)
const - return Rational(numv.den denv.num,
denv.den) -
- bool Rationaloperatorlt (const Rational v)
const - return numv.den lt denv.num
- // ...
70- Rationaloperator double() const
- return double(num)/den
-
- void Rationalreduce()
- int divisor, tmpnum
- // tmpnum is the absolute value of the numerator
- tmpnum ( num lt 0 ) ? -num num
- // standardize 0/1
- if ( num 0 )
- den 1
- else
- divisor gcd( tmpnum, den )
- if ( divisor ! 1 )
- num / divisor
- den / divisor
71- istream operatorgtgt (istream in, Rational v)
- char c // reads the speartor /
- in gtgt v.num gtgt c gtgt v.den
- if ( v.den 0 )
- cerr ltlt "Error zero denominator \n"
- exit(1)
-
- v.standardize()
- return in
-
- // ...
72Operator Overloading for ClassTemplate
- Example
- templatelt class T gt
- class Matrix
- public
- Matrix(int,int)
- Matrix(Matrix)
- Matrix()
- Matrixlt T gt operator( const Matrixlt T gt ) const
- Matrixlt T gt operator( const Matrixlt T gt )
- // ...
- private
- T _mat
- int _m, _n
73Operator Overloading for ClassTemplate
- templatelt class T gt
- Matrixlt T gt Matrixlt T gt operator(const Matrixlt
T gt m) const - MatrixltTgt tmp(_m, _n)
- for ( int i0 ilt_m i )
- for ( int j0 jlt_n j )
- tmp._matij m._matij _matij
- return tmp
-
- // rest omitted