cpsc 252 operator overloading and convert constructors page 1 operator overloading we would like to...
TRANSCRIPT
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.
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
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;};
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
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 );
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;}
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?
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 );}
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
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 ) ;
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
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
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 );
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;}
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 );
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
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
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
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;
}
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
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;
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
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
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
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 );
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
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
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!