Operator overloading - PowerPoint PPT Presentation

1 / 31
About This Presentation
Title:

Operator overloading

Description:

... (a c) i (b d) z1 z2 = (a c) i (b d) z1 * z2 = (ac bd ) i ... supply a convert constructor that converts a double to an object of type Complex ... – PowerPoint PPT presentation

Number of Views:58
Avg rating:3.0/5.0
Slides: 32
Provided by: ugrad2
Category:

less

Transcript and Presenter's Notes

Title: Operator overloading


1
  • Operator overloading
  • We would like to assign an element to a vector or
    retrieve an element stored in a vector using the
    indexing operator rather than the at() member
    function
  • IntVector myVector( 4 )
  • myVector2 34
  • cout ltlt myVector2 ltlt endl
  • We will see how to add this to the IntVector
    class
  • we need to overload the indexing operator
  • we will first examine operator overloading for
    the simpler Complex class
  • then we will return to the IntVector class.

2
The complex number class Complex numbers have the
form a ib where a and b are real numbers and
i is such that i2 -1 Suppose that z1aib and
that z2cid then z1 z2 (a c) i (b
d) z1 z2 (a c) i (b d) z1 z2 (ac
bd ) i (ad bc) z1 / z2 ( (ac bd) i (bc
ad) ) / (c2 d2) Let us now consider a
declaration of the Complex class
3
class Complexpublic // not yet complete
Complex( void ) //Post complex number is 0
0i Complex( double real, double imag )
//Post complex number is real imagi
void setComplex( double real, double imag )
//Post complex number is real imagi
double getReal( void ) const //Post real
part has been returned double getImag( void )
const //Post imaginary part has been
returned private double realPart
double imagPart
4
  • Implementing complex arithmetic in C
  • the basic member functions are easy
  • a complete version is on the course website
  • we will focus on adding overloaded operators
  • A client can perform operations such as
  • Complex num( 5, 4 )
  • cout ltlt Real part ltlt num.getReal() ltlt
    Imaginary part ltlt num.getImag() ltlt endl
  • But code such as the following will not compile
  • Complex num1( 5, 4), num2( 6, 4), num3
  • num3 num1 num2
  • Reason the operator has not been defined
    when the left and right operands are of type
    Complex

5
  • Overloading operators in C
  • We can define how to add two objects of type
    Complex
  • Any binary operator can be
  • overloaded as a member function of a C class
  • the left operand must be an instance of that
    class
  • Lets recall our client code
  • num3 num1 num2
  • the left operand is of type Complex
  • so we can define an overloaded operator
  • the alternate syntax for invoking operators is
  • num3 num1.operator( num2 )

6
Overloaded addition operator Declaration of
operator (header file / class declaration)
Complex operator( const Complex rComplex )
const Implementation (source file / class
definition) Complex Complexoperator( const
Complex rComplex ) const Complex
sum sum.realPart realPart
rComplex.realPart sum.imagPart imagPart
rComplex.imagPart return sum
7
Overloaded subtraction operator (no temp
variable) Declaration of - operator (header file
/ class declaration) Complex operator-(
const Complex rComplex ) const Implementation
(source file / class definition) Complex
Complexoperator-( const Complex
rComplex ) const return Complex( realPart -
rComplex.realPart, imagPart -
rComplex.imagPart ) We use the parameterized
constructor to avoid a local variable
8
  • Other overloaded operators in Complex
  • The binary arithmetic operators can all be
    overloaded
  • subtraction operator
  • multiplication operator
  • division operator/
  • What about the assignment operator?
  • no need to define operator
  • the compiler-provided default works just fine
  • component-wise assignment is what we want for
    Complex
  • Are there others operators we need to overload?

9
Overloading the strictly less than operator One
complex number is less than another iff both
parts are less than the others parts Declaration
of lt operator (header file / class declaration)
bool operatorlt( const Complex rComplex )
const Implementation (source file / class
definition) bool Complexoperatorlt( const
Complex rComplex ) const return
( realPart lt rComplex.realPart ) (
imagPart lt rComplex.imagPart ) Not quite.
One part has to be strictly less than, the other
can be equal.
10
Overloading other comparison operators Declaration
of lt operator does not tell the compiler about
gt lt gt ! Each of these
must be declared (and defined) separately! bool
Complexoperatorgt( const Complex
rComplex ) const return ( realPart gt
rComplex.realPart ) ( imagPart gt
rComplex.imagPart ) You might think the
compiler would synthesize a component-by-component
operator, but it will not.
11
  • Input and output operators
  • Consider the following client code
  • Complex num1, num2, num3cout ltlt Please enter
    two complex numbers (aib)cin gtgt num1 gtgt
    num2num3 num1 num2cout ltlt First num
    Second num ltlt num3 ltlt endl
  • the compiler now has no problem adding num1 and
    num2
  • but it does not know how to extract a complex
    number from an input stream
  • and it doesnt know how to insert one into an
    output stream
  • We must provide overloaded ltlt and gtgt
    operators

12
  • Stream (I/O) variables
  • the variable cin is an instance of a class named
    istream
  • the variable cout is an instance of a class
    named ostream
  • they are declared in the library header
    ltiostreamgt
  • Consider the following client code
  • Complex num( 3, 4 )
  • cout ltlt num ltlt endl
  • the ltlt operator is left associative
  • it returns a reference to its left operand when
    it is evaluated (just like )
  • the expression above is evaluated as
  • ( ( cout ltlt num ) ltlt endl )

13
  • Overloading the ltlt operator for the Complex class
  • the left operand is an instance of the ostream
    class
  • it is not an instance of the Complex class.
  • so the ltlt operator cannot be overloaded in
    Complex
  • We therefore must declare the ltlt operator as a
    friend
  • friend ostream operatorltlt( ostream
    outStream, const Complex number )
  • the friend declaration appears within the class
    declaration
  • a friend of a class is not a member function of
    the class
  • however, it can access the private members of
    the class
  • it cannot change the private members because of
    the const

14
Implementing the ltlt operator for the Complex
class ostream operatorltlt( ostream outStream
, const Complex number ) //
Non-member function // Uses cout and ltlt from
iostream library // Uses fabs() from cmath
library // Pre outStream is a valid ostream //
Post number is output to the given ostream in //
the form realPart /- imagParti
outStream ltlt number.realPart ltlt (
number.imagPart lt 0 ? "-" "" )
ltlt fabs( number.imagPart ) ltlt "i"
return outStream C
math absolute value function
15
Operator precedence In C operators are applied
in order of their precedence outStream ltlt
number.getReal() ltlt (
number.getImag() lt 0 ? "-" "" )
ltlt fabs( number.getImag() ) ltlt
"i" return outStream Parentheses are
required for this expression because of
precedence in this example C conditional
operator boolean ?
expression expression
16
  • Overloading the gtgt operator for the Complex class
  • the left operand is an instance of the istream
    class
  • it is not an instance of the Complex class.
  • so we (again) declare the gtgt operator as a
    friend
  • friend istream operatorgtgt( istream
    inStream, const Complex number )
  • Consider the following client code
  • Complex num1, num2
  • cin gtgt num1 gtgt num2
  • the gtgt operator is (again) left associative
  • and it returns a reference to its left operand
  • ( ( cin gtgt num1 ) gtgt num2 )

17
Implementing the gtgt operator for the Complex
class istream operatorgtgt( istream inStream ,
Complex number ) //
Non-member friend function // Uses cin and gtgt
from iostream library // Pre inStream is a valid
istream input is valid // Post number has been
read from the keyboard with // format
realPart/-imagParti with no spaces
char iChar // used to read 'i, which is
ignored inStream gtgt number.realPart
gtgt number.imagPart gtgt iChar
return inStream
18
  • A caution about declaring friend methods
  • Declaring a function to be a friend violates the
    principle of encapsulation
  • a function external to the class can access
    private data
  • a function external to the class can change
    private data
  • a function external to the class can invoke
    private methods
  • normally we do not want to allow this
  • sometimes we have to do this, as for ltlt and gtgt
  • only do this when it is absolutely necessary
  • we can declare a non-friend function calling
    public methods
  • istream operatorgtgt( istream inStream,
  • Complex number )

19
Non-friend ltlt operator for the Complex class
ostream operatorltlt( ostream outStream ,
const Complex number ) //
Non-member non-friend function // Uses cout and
ltlt from iostream library // Uses fabs() from
cmath library // Pre outStream is a valid
ostream // Post number is output to the given
ostream in // the form realPart /-
imagParti outStream ltlt number.getReal()
ltlt ( number.getImag() lt 0 ? "-" ""
) ltlt fabs( number.getImag() )
ltlt "i" return outStream Less
efficient because of method calls, but not too
ineffcient
20
Non-friend gtgt operator for the Complex class
istream operatorgtgt( istream inStream ,
Complex number ) // Non-member
friend function // Uses cin and gtgt from iostream
library // Pre inStream is a valid istream
input is valid // Post number has been read from
the keyboard with // format
realPart/-imagParti with no spaces
char iChar // used to read 'i'
double real, imag // read the
two parts inStream gtgt real gtgt imag gtgt
iChar Complex value( real, imag ) // build
result number value // set
value return inStream Less efficient
because of method calls, but not too ineffcient
21
  • Overloading other operators (mixing types)
  • Now consider the following client code that will
    not compile
  • Complex num1( 4.5, 5.0), num2double value
    5.5
  • num2 num1 value
  • the overloaded operator only works when both
    operands are of type Complex
  • but here the right operand is of type double.
  • We can now proceed in two ways
  • supply another overloaded operator that takes
    a left operand of type Complex and a right
    operand of type double
  • supply a convert constructor that converts a
    double to an object of type Complex

22
Option 1 Supply another overloaded operator
Complex Complexoperator( const double
right ) const // Member operator function //
Post the sum of this Complex and the double
right is returned Complex sum
sum.realPart realPart right sum.imagPart
imagPart return sum
23
  • Option 2 Supply a convert constructor
  • Declaration in the header file
  • Complex( double num )//Post complex number is
    num 0i
  • Implementation in the source file
  • ComplexComplex( double num )
  • //Post complex number is num 0i
  • realPart num
  • imagPart 0.0
  • can be called explicitly in client code
  • can also be called implicitly by the compiler as
    needed

24
Explicit conversion The programmer specifies use
of a conversion constructor Complex num1( 4.5,
5.0), num2double value 5.5 num2 num1
Complex( value ) This is an example of type
casting (or type conversion) double num
6.785int rounded int( num 0.5 ) or char
alpha Acout ltlt int( alpha ) ltlt endl
25
Implicit conversion The compiler decides to use
a conversion constructor void myFunc( Complex
param ) double value 5.5 myFunc( value
) The convert constructor is called implicitly
to convert value to a Complex when it is passed
as a parameter to myFunc
26
  • Which is best Option 1 or Option 2?
  • Advantages for Option 1
  • no implicit conversion
  • the more explicit our code is, the easier it is
    to debug
  • Disadvantage for Option 1
  • we may have to overload other versions of the
    operator
  • Complex operator( double num, const Complex
    rComplex)//Post the sum of (num 0i) and
    rComplex is//returned
  • double num 6.5Complex complex1( 5.5, 3.5 ),
    complex2
  • complex2 num complex1
  • Left operand is double and right operand is
    Complex

27
  • Advantages for Option 2
  • a single constructor that converts a double to
    Complex
  • one version of the overloaded operator
  • we can perform addition on many combinations of
    operands
  • double num 6.5Complex complex1( 5.5, 3.5 ),
    complex2( 0.5, 1.5 ), complex3
  • complex3 complex1 complex2complex3
    Complex( num ) complex2complex3 complex1
    Complex( num )
  • Disadvantage
  • objects can be implicitly converted by the
    compiler
  • this can sometimes lead to code that is
    difficult to debug

28
  • The explicit keyword
  • The disadvantage of Option 2 can be removed by
    using the explicit keyword
  • add this keyword to the declaration of the
    constructor
  • this prevents the compiler from implicitly
    converting
  • so a double will not become a Complex
  • only explicit invocations of the convert
    constructor are allowed
  • public explicit Complex( double value )

29
Operator overloading the indexing operator We
now (finally) overload the indexing operator
for our IntVector class. For the same reason
that we have two versions of the at() member
function, we need to declare two versions of the
overloaded indexing operator Accessor int
operator( int index ) const// Post if 0 lt
index lt size() the element at// index is
returned, otherwise program aborted Mutator int
operator( int index )// Post if 0 lt index lt
size() the element at// index is returned,
otherwise program aborted
30
  • Implementing the overloading indexing operator
  • The implementation is exactly the same as the
    corresponding at() functions
  • simply call the at() function in the operator
    function
  • int IntVectoroperator( int index ) const
    return at( index )
  • this is concise
  • but it is a little inefficient because of the
    function call
  • this operator may be called many times by a
    client
  • duplicating the code in at() is more efficient
  • but code is bloated if we have blocks of
    duplicate code

31
  • The inline keyword
  • We can actually have the best of both approaches
  • the concise version of the operator
  • no overhead for a function call to at(
  • inline int at( int index ) const return
    value index
  • The inline keyword suggests that
  • the compiler should replace each call to the
    inline function with the body of that function
  • the compiler should avoid the function call
  • the compiler can ignore the inline keyword if it
    sees fit!
Write a Comment
User Comments (0)
About PowerShow.com