cpsc 252 operator overloading and convert constructors page 1 operator overloading we would like to...

28
CPSC 252 Operator Overloading and Convert Constructors Page 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 ); myVector[2] = 34; cout << myVector[2] << 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

Upload: sylvia-fitzgerald

Post on 05-Jan-2016

226 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 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 );

myVector[2] = 34;

cout << myVector[2] << 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.

Page 2: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 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 z1=a+ib and that z2=c+id 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

Page 3: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 3

class Complex{public: // not yet complete Complex( void ); //Post: complex number is 0 + 0*i Complex( double real, double imag ); //Post: complex number is real + imag*i

void setComplex( double real, double imag ); //Post: complex number is real + imag*i 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;};

Page 4: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 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 << “Real part:” << num.getReal() << “Imaginary part:” << num.getImag() << endl;

But code such as the following will not compile:

Complex num1( 5, 4), num2( 6, 4), num3;

num3 = num1 + num2;

Reason: the “+” operator is not been defined when the left and right operands are of type Complex

Page 5: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 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

Let’s 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 );

Page 6: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 6

Overloaded addition operator

Declaration of + operator (header file / class declaration):

Complex operator+( const Complex& rComplex ) const;

Implementation (source file / class definition):

Complex Complex::operator+( const Complex& rComplex ) const

{ Complex sum;

sum.realPart = realPart + rComplex.realPart;

sum.imagPart = imagPart + rComplex.imagPart;

return sum;}

Page 7: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 7

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?

Page 8: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 8

Overloaded the “strictly less than” operator

One complex numbers less than another iff both parts are strictly less than the other’s parts

Declaration of < operator (header file / class declaration):

bool operator<( const Complex& rComplex ) const;

Implementation (source file / class definition):

bool Complex::operator<( const Complex& rComplex ) const

{ return ( realPart < rComplex.realPart )

&& ( imagPart < rComplex.imagPart );}

Page 9: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 9

Input and output operators

Consider the following client code:

Complex num1, num2, num3;

cout << “Please enter two complex numbers (a+ib):”;cin >> num1 >> num2;

num3 = num1 + num2;cout << “First num + Second num =“ << num3 << 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 doesn’t know how to insert one into an output stream

We must provide overloaded “<<” and “>>” operators

Page 10: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 10

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 <iostream>

Consider the following client code:

Complex num( 3, 4 );

cout << num << endl;

• the << operator is left associative

• it returns the left operand when it is evaluated (just like “=”)

• the expression above is evaluated as:

( ( cout << num ) << endl ) ;

Page 11: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 11

Overloading the << 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 << operator cannot be overloaded in Complex

We therefore must declare the << operator as a friend

friend ostream& operator<<( 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

Page 12: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 12

Implementing the << operator for the Complex class

ostream& operator<<( ostream& outStream , const Complex& number )// Non-member function// Uses cout and << 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] +/- [imagPart]i{ outStream << number.realPart << ( number.imagPart < 0 ? "-" : "+" ) << fabs( number.imagPart ) << "i"; return outStream;}

C++ “math” absolute value function

Page 13: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 13

Overloading the >> 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 >> operator as a friend

friend istream& operator>>( istream& inStream, const Complex& number );

Consider the following client code:

Complex num1, num2;

cin >> num1 >> num2;

• the >> operator is (again) left associative

• and it returns its left operand

( ( cin >> num1 ) >> num2 );

Page 14: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 14

Implementing the >> operator for the Complex class

istream& operator>>( istream& inStream , Complex& number )// Non-member friend function// Uses cin and >> from iostream library// Pre: inStream is a valid istream// Post: number has been read from the keyboard with// format: [realPart]+/-[imagPart]i with no spaces{ char iChar; // used to read 'i’, which is ignored

inStream >> number.realPart >> number.imagPart >> iChar ; return inStream;}

Page 15: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 15

A caution about declaring “friend” methods

Declaring a function to be a friend violating 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 << and >>

• only do this when it is absolutely necessary

• we can declare a non-friend function calling public methods

istream& operator>>( istream& inStream,

const Complex& number );

Page 16: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 16

Non-friend << operator for the Complex class

ostream& operator<<( ostream& outStream , const Complex& number )// Non-member non-friend function// Uses cout and << 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] +/- [imagPart]i{ outStream << number.getReal() << ( number.getImag() < 0 ? "-" : "+" ) << fabs( number.getImag() ) << "i"; return outStream;}

Less efficient because of method calls, but not too ineffcient

Page 17: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 17

Operator precedence

In C++ operators are applied in order of their precedence

{ outStream << number.getReal() << ( number.getImag() < 0 ? "-" : "+" ) << fabs( number.getImag() ) << "i"; return outStream;}

Parentheses are required for this expression because of precedence in this example

C++ conditional operator: boolean ? expression : expression

Page 18: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 18

Overloading other operators (mixing types)

Now consider the following client code that will not compile:

Complex num1( 4.5, 5.0), num2;double 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

Page 19: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 19

Option 1: Supply another overloaded + operator

Complex Complex::operator+( 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;

}

Page 20: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 20

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:

Complex::Complex( 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

Page 21: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 21

Explicit conversion

The programmer specifies use of a conversion constructor

Complex num1( 4.5, 5.0), num2;double value = 5.5;

num2 = num1 + Complex( value );

This is an example of type casting (or type conversion)

double num = 6.785;int rounded = int( num + 0.5 );

or

char alpha = ‘A’;cout << int( alpha ) << endl;

Page 22: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 22

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

Page 23: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 23

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.5;Complex complex1( 5.5, 3.5 ), complex2;

complex2 = num + complex1;

Left operand is double and right operand is Complex

Page 24: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 24

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.5;Complex complex1( 5.5, 3.5 ),

complex2( 0.5, 1.5 ), complex3;

complex3 = complex1 + complex2;complex3 = Complex( num ) + complex2;complex3 = complex1 + Complex( num );

Disadvantage:

• objects can be implicitly converted by the compiler

• this can sometimes lead to code that is difficult to debug

Page 25: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 25

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 );

Page 26: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 26

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 <= index < size() the element at// index is returned, otherwise program aborted

Mutator:

int& operator[]( int index );// Post: if 0 <= index < size() the element at// index is returned, otherwise program aborted

Page 27: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 27

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 IntVector::operator[]( 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

Page 28: CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element

CPSC 252 Operator Overloading and Convert Constructors Page 28

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!