software design and c programming
Download
Skip this Video
Download Presentation
Software Design and C++ Programming

Loading in 2 Seconds...

play fullscreen
1 / 56

Software Design and C++ Programming - PowerPoint PPT Presentation


  • 59 Views
  • Uploaded on

Software Design and C++ Programming. Lecture 4 Operator Overloading and Streamed I/O. Contents. Introduction Operators in C++ Operator overload functions Member function v friend function overloading Converting between types Overloading the assignment operator

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Software Design and C++ Programming' - quito


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
software design and c programming

Software Design and C++ Programming

Lecture 4

Operator Overloading and Streamed I/O

contents
Contents
  • Introduction
  • Operators in C++
  • Operator overload functions
  • Member function v friend function overloading
  • Converting between types
  • Overloading the assignment operator
  • Overloading the array subscripting operator
  • Example – A Date class
  • Introduction to streams
  • The ostream and istream classes
  • User defined input/ouput
  • Other features of streams
introduction
Introduction
  • Operator overloading is a powerful feature of C++
  • It provides programmers with a concise notation for manipulating user defined objects
  • 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
operators in c
Operators in C++
  • C++ has a rich collection of operators most of which are common to other programming languages
  • It is the standard arithmetic and logical operators
    • + - * / % & ! >> << || && == etc
  • It has thearray indexing and function evaluation operators
    • [] ()
  • It has the assignment operators
    • = += -= *= /= &= |= etc
slide5
It has the auto increment and decrement operators
    • ++ --
  • It has the pointer de-referencing and address of operators
    • * &
  • It has the memory management operators
    • new delete new[] delete[]
slide6
We can divide up the set of operators into unary and binary operators
  • A unary operator has one operand
  • 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

slide7
A binary operator has two operands
  • 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

operator overload functions
Operator overload functions
  • 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)
slide9
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
example
Example
  • 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);

};

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

}

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

};

slide13

complex complex::operator +(complex a)

{

return complex(re + a.re , im + a.im);

}

complex complex::operator -()

{

return complex(-re, -im);

}

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

}

slide15
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
converting between types
Converting between types
  • 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
    • Conversion constructor
    • Conversion operator
conversion constructor
Conversion constructor
  • Suppose we wanted to write the following simple piece of code

void main()

{

complex z1,z2;

z1 = z2 + 3.0;

}

slide18
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

complex :: complex(double d)

{

re = d;

im = 0;

}

slide19
z2+3.0 is now interpreted as :

operator+(z2,complex(3.0))

  • 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)
  • Member function implementation of z2+3.0 is z2.operator(complex(3.0))
  • There is no equivalent implementation of 3.0+z2
conversion operator
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)
  • 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
slide21
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;}

};

slide22
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

}

overloading the assignment operator
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
  • 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
slide24
We can see how assignment overload becomes important by considering a simple String class
    • Memory for the string is allocated dynamically in the constructor
slide25

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

};

slide26
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?

}

slide27

“a”, “b”, “c”,

“a”, “b”, “c”,

Before assignment

s1.p

s2.p

“d”, “e”, “f”,

After assignment

s1.p

“d”, “e”, “f”,

s2.p

slide28
An assignment overload operatordefined asString& 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;

}

slide29

“a”, “b”, “c”,

“d”, “e”, “f”,

Before assignment

s1.p

s2.p

“d”, “e”, “f”,

After assignment

s1.p

s2.p

“d”, “e”, “f”,

slide30
Why does operator=(String) return a String reference?
  • Assignment as 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
overloading the array subscripting operator
Overloading the array subscripting operator
  • 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
slide32

class SafeArray

{

private:

int* data;

int numPoints;

public:

SafeArray(int);

int& operator[](int);

};

slide33

int& SafeArray::operator[](int index)

{

if ((index<0)||(index>=numPoints))

{

printf( “Index array out of range ”);

exit(1); // exit program

}

return data[index];

}

slide34
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!

}

example a date class
Example. A Date class
  • 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
slide36

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;

};

slide37
days[] is a convenience array for storing the days per month
  • 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)

const int Date::days[]=

{0,31,28,31,30,31,30,31,31,30,31,30,31};

slide38

void Date::helpIncrement()

{

if (!endOfMonth(day))

++day;

else

if (month<12)

{

++month;

day=1;

}

else

{

++year;

month=day=1;

}

}

slide39

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

}

slide40
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
    • In any case syntax such as Date d++=… is not allowed
slide41

Introduction to streams

  • C++ provides an extensive set of input/output capabilities
  • 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
slide42

The ostream and istream classes

  • 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 << and >> operators
    • << - stream insertion operator for output
    • >> - stream extraction operator for input
  • Overload functions for the primitive types are provided
  • Overload functions can easily be provided for programmer defined classes
slide43

The ostream class

class ostream

{

.

.

public :

ostream& operator << (const char*);

ostream& operator<<(char);

ostream& operator<<(int);

ostream& operator<<(double);

ostream& operator<<(const void*);

.

.

}

slide44

All C++ programs have access to an ostream object cout

  • 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
slide45

Example

int x=10;

cout << "x = " << x; // Outputs “x= 10”

  • Implemented as (cout.operator<<(“x=“)).operator<<(x);
  • Overload functions ostream.operator<<(char*) and ostream.operator<<(int) called
slide46

The istream class

class istream

{

.

.

public :

istream& operator >> (char*);

istream& operator>>(char&);

istream& operator>>(int&);

istream& operator>>(double&);

.

.

}

slide47

All C++ programs have access to an istream object cin

  • 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
  • operator>>() functions skips white space characters (blanks, tabs, newline, formfeed, carriage return) on the input stream in the same way as scanf() )
slide48

Example

void main()

{

int i1, i2;

float f;

cout << "Input 2 ints and a float \n";

cin >> i1 >> i2 >> f;

}

slide49

Using right to left associativity, the input is implemented as(((cin >> i1) >> i2) >> f);

  • 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!
slide50

User defined input/ouput

  • We can add overloaded operator>>() and operator<<() functions to our own classes
  • 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
slide51

Example

  • We can add input and output facilities to our Date class
  • Enables a user friendly way of displaying and inputting the current date
slide52

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;

};

slide53

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;

return os;

};

istream& operator>>(istream& is, Date& d)

{

cout<<“Input the date (dd/mm/yy) “;

is >> d.day >> d.month >> d.year;

return is;

};

slide54

void main()

{

Date d;

cout << “Input the date : “;

cin >> d;

cout << “The date is “ << d;

}

and finally
And finally…..
  • 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
  • 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
slide56
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())
ad