Download presentation
Presentation is loading. Please wait.
Published byNoreen Grant Modified over 8 years ago
1
EE4E. C++ Programming Lecture 4 Operator Overloading and Streamed I/O
2
Contents Introduction Introduction Operators in C++ Operators in C++ Operator overload functions Operator overload functions Member function v friend function overloading Member function v friend function overloading Converting between types Converting between types Overloading the assignment operator Overloading the assignment operator Overloading the array subscripting operator Overloading the array subscripting operator Example – A Date class Example – A Date class Introduction to streams Introduction to streams The ostream and istream classes The ostream and istream classes User defined input/ouput User defined input/ouput Other features of streams Other features of streams
3
Introduction Operator overloading is a powerful feature of C++ Operator overloading is a powerful feature of C++ It provides programmers with a concise notation for manipulating user defined objects It provides programmers with a concise notation for manipulating user defined objects It is simple to implement given a few basic rules It is simple to implement given a few basic rules It is also used in providing input/output capabilities via the Stream classes as we shall see in the next lecture It is also used in providing input/output capabilities via the Stream classes as we shall see in the next lecture
4
Operators in C++ C++ has a rich collection of operators most of which are common to other programming languages C++ has a rich collection of operators most of which are common to other programming languages It is the standard arithmetic and logical operators It is the standard arithmetic and logical operators + - * / % & ! >> > << || && == etc It has the array indexing and function evaluation operators It has the array indexing and function evaluation operators [] () It has the assignment operators It has the assignment operators = += -= *= /= &= |= etc
5
It has the auto increment and decrement operators It has the auto increment and decrement operators ++ -- It has the pointer de-referencing and address of operators It has the pointer de-referencing and address of operators * & It has the memory management operators It has the memory management operators new delete new[] delete[]
6
We can divide up the set of operators into unary and binary operators We can divide up the set of operators into unary and binary operators A unary operator has one operand A unary operator has one operand Examples Examples if (!x){..}// unary operator !, operand x x++;// post-fix operator ++, operand x --x;// pre-fix operator --, operand x int y=a[5];// operator [], operand a
7
A binary operator has two operands A binary operator has two operands Examples Examples int z=x+y;// binary operator +, operands x and y bool z=x&&y;// binary operator && operands x and y x+=y;// binary operator +=, operands x and y
8
Operator overload functions In order to overload and operator op, a function operator op must be defined In order to overload and operator op, a function operator op must be defined operator+ to overload + operator+= to overload += operator[] to overload [] etc We can either provide member functions of a class or external functions (possibly friend functions of a class) We can either provide member functions of a class or external functions (possibly friend functions of a class)
9
Restrictions on operator overloading Restrictions on operator overloading The precedence of an operator cannot be changed The arity of an operator cannot be changed We cannot redefine a binary operator to be unary or vice verse The associativity of an operator cannot change Whether it applies left to right or right to left
10
Example We can define a complex class to represent a complex number We can define a complex class to represent a complex number class complex { private : double re, im; public : complex(double r,double i) { re = r; im = i;} friend complex operator +(complex, complex); friend complex operator -(complex); };
11
We have included 2 friend functions for overloading the binary + operator and unary - operator We have included 2 friend functions for overloading the binary + operator and unary - operator complex operator +(complex a,complex b) { return complex(a.re + b.re, a.im + b.im); } complex operator -(complex a) { return complex(-a.re, -a.im); }
12
We can also implement the overload functions as member functions We can also implement the overload functions as member functions In this case, this replaces one of the arguments class complex { private : double re, im; public : complex(double r,double i) { re = r; im = i;} complex operator +(complex); complex operator -(); };
13
complex complex::operator +(complex a) { return complex(re + a.re, im + a.im); } complex complex::operator -() { return complex(-re, -im); }
14
The class can now be used as follows The class can now be used as follows void main() { complex z1(3.0,2.0),z2(3.0,-5.0),z3,z4; z3 = z1 + z2;// overload operator+ z4=-z3;// overload operator- }
15
z1 + z2 is implemented as operator+(z1,z2) when a global function overload is used and z1.operator+(z2) when a member function overload is used z1 + z2 is implemented as operator+(z1,z2) when a global function overload is used and z1.operator+(z2) when a member function overload is used -z3 is implemented as operator-(z3) when a global function overload is used and z3.operator-() when a member function overload is used -z3 is implemented as operator-(z3) when a global function overload is used and z3.operator-() when a member function overload is used
16
Converting between types It is often necessary to convert data of one type into data of another type It is often necessary to convert data of one type into data of another type This is done implicitly by the compiler when we, for example, add an integer variable to a floating point variable However, for user defined types, the compiler cannot know in advance how to do these conversions Two mechanisms exist in C++ to convert data types Two mechanisms exist in C++ to convert data types Conversion constructor Conversion operator
17
Conversion constructor Suppose we wanted to write the following simple piece of code Suppose we wanted to write the following simple piece of code void main() { complex z1,z2; z1 = z2 + 3.0; }
18
We could write an operator overload function operator+(complex,double) We could write an operator overload function operator+(complex,double) But we would need to repeat this for every other operator (eg. -,*,/) The solution is to write a complex->double conversion constructor The solution is to write a complex->double conversion constructor complex :: complex(double d) { re = d; im = 0; }
19
z2+3.0 is now interpreted as : z2+3.0 is now interpreted as : operator+(z2,complex(3.0)) operator+(z2,complex(3.0)) This will cause problems if we have implemented operator+() as a member function This will cause problems if we have implemented operator+() as a member function z2+3.0 must be interpreted in the same way as 3.0+z2 (addition is commutative) z2+3.0 must be interpreted in the same way as 3.0+z2 (addition is commutative) Member function implementation of z2+3.0 is z2.operator(complex(3.0)) Member function implementation of z2+3.0 is z2.operator(complex(3.0)) There is no equivalent implementation of 3.0+z2 There is no equivalent implementation of 3.0+z2
20
Conversion operator This is used to to convert an object of one class into an object of another class or into a built in type (int, float, char etc) This is used to to convert an object of one class into an object of another class or into a built in type (int, float, char etc) Sometimes called a cast operator as it essentially overloads the cast () operation Sometimes called a cast operator as it essentially overloads the cast () operation Declared as a member function of some class, operator X() specifies how to convert an object of this class into an object of type X Declared as a member function of some class, operator X() specifies how to convert an object of this class into an object of type X
21
As a (silly) example, we could define a member function double() to convert a complex to a double by taking the real part As a (silly) example, we could define a member function double() to convert a complex to a double by taking the real part class complex { private : double re, im; public : complex(double r,double i) { re = r; im = i;} operator double() {return re;} };
22
If we then cast a complex to a double, the conversion operator is called If we then cast a complex to a double, the conversion operator is called void main() { complex z1(1,0,2.0); double x=(double) z1;// calls double(), x=1.0 }
23
Overloading the assignment operator A powerful feature of operator overloading is overloading the assignment operator = A powerful feature of operator overloading is overloading the assignment operator = This allows us to specify the action of the statement a=b for two objects a and b of some class This allows us to specify the action of the statement a=b for two objects a and b of some class For our simple complex class, implementing operator= is not necessary For our simple complex class, implementing operator= is not necessary z1=z2 causes a default member-wise assignment to be implemented z1.re=z2.re, z1.im=z2.im
24
We can see how assignment overload becomes important by considering a simple String class We can see how assignment overload becomes important by considering a simple String class Memory for the string is allocated dynamically in the constructor
25
class String {private: char *p;// pointer to string data int size;// length of string public: String (int sz) { p = new char[size = sz];} ~String( ); int getSize( ) { return size; } char* getp( ) { return p;} };
26
Without an overloaded assignment operator, assignment involves member-wise copy which doesn’t transfer the data Without an overloaded assignment operator, assignment involves member-wise copy which doesn’t transfer the data It just copies the pointers main( ) { string s1(3);// string of 3 chars string s2(3);// string of 3 chars s1 = s2;// are you sure? }
27
s1.p s2.p “a”, “b”, “c”, “d”, “e”, “f”, After assignment Before assignment “d”, “e”, “f”, s2.p s1.p “a”, “b”, “c”,
28
An assignment overload operator defined as String& String::operator = (String& a) uses strcpy() to ensure data is copied An assignment overload operator defined as String& String::operator = (String& a) uses strcpy() to ensure data is copied String& String::operator = (String& a) { if (this != &a)// avoid s = s assignment { delete p; p = new char[size = a.getSize( )]; strcpy(p,a.getp( ));// copy *a.p into *p } return *this; }
29
s1.p s2.p “a”, “b”, “c”, “d”, “e”, “f”, After assignment Before assignment “d”, “e”, “f”, s2.p s1.p “d”, “e”, “f”,
30
Why does operator=(String) return a String reference? Why does operator=(String) return a String reference? Assignment has a right to left associativity A statement like x=y=z is implemented as (x=(y=z)) The result of y=z is a reference to object y This then appears in the x=y assignment This ‘trick’ is also extensively used in streamed i/o
31
Overloading the array subscripting operator The [] operator normally used for array access can be overloaded The [] operator normally used for array access can be overloaded It enables us to design a safe array class where attempts to access beyond the bounds of the array are flagged
32
class SafeArray {private: int* data; int numPoints; public:SafeArray(int); int& operator[](int); };
33
int& SafeArray::operator[](int index) { if ((index =numPoints)) { printf( “Index array out of range ”); exit(1);// exit program } return data[index]; }
34
Why does operator[] return a reference? Why does operator[] return a reference? Allows array values to be set as well as accessed using the overload function In other words, the returned value can be used as an lvalue void main() { SafeArray sa(10);// 10 point safe array int j=sa[3];// Access value sa[5]=5;// Set value int k=sa[10];// Out of range! }
35
Example. A Date class We can design a Date class which uses overloaded ++ operator functions to add 1 to the day We can design a Date class which uses overloaded ++ operator functions to add 1 to the day Program statements such as date++ and ++date will then increment the date We have to think carefully about the differences between the post and pre-increment overload functions
36
class Date {private: int day,month,year; void helpIncrement(); static const int days[]; public: Date(int d, int m, int y) {day=d;month=m;year=y;} Date& operator++();// pre-increment Date operator++(int);// post-increment int endOfMonth(int) const; int leapYear(int) const; };
37
By convention in C++ the post increment (x++) expression calls the overload function with a dummy integer argument By convention in C++ the post increment (x++) expression calls the overload function with a dummy integer argument days[] is a convenience array for storing the days per month days[] is a convenience array for storing the days per month helpIncrement() is a convenience function for helping to increment the day helpIncrement() is a convenience function for helping to increment the day endOfMonth() uses the days[] array to determine if a given day is the last in the month (taking into account leap years) endOfMonth() uses the days[] array to determine if a given day is the last in the month (taking into account leap years) const int Date::days[]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
38
void Date::helpIncrement() { if (!endOfMonth(day)) ++day;else if (month<12) {++month;day=1;}else{++year;month=day=1;}}
39
Date& Date::operator++() { // Pre-increment operator helpIncrement(); return *this;// reference returned } Date Date::operator++(int) { //Post increment operator Date temp=*this;// current object state helpIncrement(); return temp;// can’t return reference }
40
The pre-increment operator overload function returns a reference so that pre- incremented Date objects can be used as lvalues (Date ++d=….) The pre-increment operator overload function returns a reference so that pre- incremented Date objects can be used as lvalues (Date ++d=….) We can’t do this for the post increment overload function as we can’t return a reference to a temporary local variable We can’t do this for the post increment overload function as we can’t return a reference to a temporary local variable In any case syntax such as Date d++=… is not allowed
41
Introduction to streams C++ provides an extensive set of input/output capabilities C++ provides an extensive set of input/output capabilities Stream based input/output relies extensively on operator overloading as well as being object oriented Stream based input/output relies extensively on operator overloading as well as being object oriented Specific I/O routines are called depending on the data type of the object being input or output Users can specify how to perform I/O for objects or programmer defined types Users can specify how to perform I/O for objects or programmer defined types
42
The ostream and istream classes The iostream library provides the ostream class for stream-based output and the istream class for stream-based input The iostream library provides the ostream class for stream-based output and the istream class for stream-based input These classes provide overload functions for the > operators These classes provide overload functions for the > operators << - stream insertion operator for output >> - stream extraction operator for input Overload functions for the primitive types are provided Overload functions for the primitive types are provided Overload functions can easily be provided for programmer defined classes Overload functions can easily be provided for programmer defined classes
43
The ostream class class ostream {.. public : ostream& operator << (const char*); ostream& operator<<(char); ostream& operator<<(int); ostream& operator<<(double); ostream& operator<<(const void*);..}
44
All C++ programs have access to an ostream object cout All C++ programs have access to an ostream object cout ostream overload functions automatically called by matching the data types ostream overload functions automatically called by matching the data types The << operator has left-to-right associativity so multiple objects can be output in one statment The << operator has left-to-right associativity so multiple objects can be output in one statment
45
Example Implemented as (cout.operator<<(“x=“)).operator<<(x); Implemented as (cout.operator<<(“x=“)).operator<<(x); Overload functions ostream.operator<<(char*) and ostream.operator<<(int) called Overload functions ostream.operator<<(char*) and ostream.operator<<(int) called int x=10; cout << "x = " << x;// Outputs “x= 10”
46
The istream class class istream {.. public : istream& operator >> (char*); istream& operator>>(char&); istream& operator>>(int&); istream& operator>>(double&);..}
47
All C++ programs have access to an istream object cin All C++ programs have access to an istream object cin istream overload functions take reference arguments as they modify the arguments istream overload functions take reference arguments as they modify the arguments The >> operator has left-to-right associativity so multiple objects can be input in one statement The >> operator has left-to-right associativity so multiple objects can be input in one statement operator>>() functions skips white space characters (blanks, tabs, newline, formfeed, carriage return) on the input stream in the same way as scanf() ) operator>>() functions skips white space characters (blanks, tabs, newline, formfeed, carriage return) on the input stream in the same way as scanf() )
48
Example void main() { int i1, i2; float f; cout << "Input 2 ints and a float \n"; cin >> i1 >> i2 >> f; }
49
Using left to right associativity, the input is implemented as (((cin >> i1) >> i2) >> f); Using left to right associativity, the input is implemented as (((cin >> i1) >> i2) >> f); operator>>(int&) is called twice and operator>>(float&) is called once operator>>(int&) is called twice and operator>>(float&) is called once The values input must be separated by whitespace characters (blanks, tabs, cr) and not commas! The values input must be separated by whitespace characters (blanks, tabs, cr) and not commas!
50
User defined input/ouput We can add overloaded operator>>() and operator >() and operator<<() functions to our own classes They must be overloaded as friend functions of the class and not member functions They must be overloaded as friend functions of the class and not member functions Obviously they are implemented as binary operators with the first operand cin or cout We must remember to return a reference to an ostream or istream object We must remember to return a reference to an ostream or istream object
51
Example We can add input and output facilities to our Date class We can add input and output facilities to our Date class Enables a user friendly way of displaying and inputting the current date
52
class Date {private: int day,month,year; void helpIncrement(); static const int days[]; public: Date(int d, int m, int y){day=d;month=m;year=y;} friend ostream& operator<<(ostream&, const Date&); friend istream& operator>>(istream&, Date&); Date& operator++();// pre-increment Date operator++(int);// post-increment int endOfMonth(int) const; int leapYear(int) const; };
53
ostream& operator<<(ostream& os, const Date& d) { static char* monthName[13]={“”,”Jan”,”Feb”,”March”,”April”,”May”,”June”,”July”,”Aug”,”Sept”,”Oct”,”Nov”,”Dec”}; os<<monthName[d.month] << “ “ << d.day << “ “ << d.year; << “ “ << d.year; return os; }; istream& operator>>(istream& is, Date& d) { cout<<“Input the date (dd/mm/yy) “; is >> d.day >> d.month >> d.year; return is; };
54
void main() { Date d; cout << “Input the date : “; cin >> d; cout << “The date is “ << d; }
55
And finally….. We have covered some basic ideas about operator overloading and streamed I/O We have covered some basic ideas about operator overloading and streamed I/O Operator overloading provides user defined classes with elegant notation for expressing manipulations of objects Operator overloading provides user defined classes with elegant notation for expressing manipulations of objects There are more advanced applications of operator overloading such as There are more advanced applications of operator overloading such as Overloading new and delete for advanced memory management routines Overloading -> and * for ‘smart’ pointer access
56
There are also more advanced features of streams including : There are also more advanced features of streams including : File access. Streams can be attached to filenames allowing the whole set of stream functionality to be applied to file I/O Formatting. Field width, field precision (for floating point output), formatting of integer output (decimal, hex, octal). String streams. Streams can be attached to arrays of characters which allows easy conversion of strings into constituent parts (similar to sprintf() and sscanf())
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.