Top Banner
Operator overloading II Output, input and other operators
43
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Operator overloading II Output, input and other operators.

Operator overloading II

Output, input and other operators

Page 2: Operator overloading II Output, input and other operators.

‘this’ example

bool Employee::operator>(const Employee& e) const{ return(this->seniority > e->seniority);}

called from the program like this: if (emp1 > emp2)

emp1 accounts for ‘this’, emp2 becomes e

Page 3: Operator overloading II Output, input and other operators.

example without ‘this’

bool Employee::operator>(const Employee& e) const{ return(seniority > e->seniority);}

called from the program like this: if (emp1 > emp2)

‘this’ is more self-documenting, but more verbose

Page 4: Operator overloading II Output, input and other operators.

Invoking objects

If the operator is binary but there is only one explicit argument, the ‘invoking instance’ is assumed to be the one on the left hand side of the expression.

Class Date{ public: // member functions

Date& operator=(const Date&);};void assign(Date& s1, Date& s2){ s1 = s2; // instead of s1.operator=(s2);}

Page 5: Operator overloading II Output, input and other operators.

Overloading output operators

iostream.h defines the cout object as an instance of the ostream class.

The iostream.h file overloads << with functions handling each of the native data types.

Example: ostream& operator<<(ostream& out, int

n);

Page 6: Operator overloading II Output, input and other operators.

operator<< overloadingostream& operator<<(ostream& out, int n);This is a non-member function (not called as

part of a particular class) therefore it needs two arguments (not one like member function operators)

It returns an ostream so that it will work in multiple call settings. cout << int1 << int2; //see last lecture for details on chaining problems.

Page 7: Operator overloading II Output, input and other operators.

Advantages

Rather than Clerk.showData(); we can do the following: cout << Clerk;

Page 8: Operator overloading II Output, input and other operators.

Problems

If operator<< is a non-member function, 1. What does it look like? 2. How can it work on private data

members of an Employee object?

Page 9: Operator overloading II Output, input and other operators.

What the non-member function looks like

ostream& operator<<(ostream& out, const Employee& emp){ out << “Employee number is “ << emp.idNum; out << “ Salary is “ << emp.salary << endl; return(out)}

a non-member function(not tied to any class)

Page 10: Operator overloading II Output, input and other operators.

How it can access private data

To do this we must place the prototype of the non-member function in the public section of the class definition.

Then, we must identify it as a ‘friend’ of the class.

A ‘friend function’ has direct access to the private data members.

Page 11: Operator overloading II Output, input and other operators.

The original employee class

class Employee{ private: int idNum; double salary; public: Employee(const int id, const double salary); double addTwo(const Employee& emp); double operator+(const Employee& emp); }

Page 12: Operator overloading II Output, input and other operators.

Non-member functions can have access to private data

class Employee{ private: int idNum; double salary; public: Employee(const int id, const double salary); double addTwo(const Employee& emp); double operator+(const Employee& emp); friend ostream& operator << (ostream &out, const Employee& emp); // the prototype for a friend function}

Page 13: Operator overloading II Output, input and other operators.

Overloading input >>

You can construct an overloaded extraction operator in a manner similar to that used for the insertion operator <<

One additional feature could be implemented as well, you could screen for invalid data as it was entered.

This would also need to be a friend function if it was not a non-member of the class.

Page 14: Operator overloading II Output, input and other operators.

Extraction operator >>

istream& operator>>(istream& in, Employee& emp){ cout << endl; // to clear the buffer cout << “Enter the employee id number “; in >> emp.idNum; cout << “Enter the salary “; in >> emp.salary; // data verification here return(in)}

to use it from client code:cin >> Clerk;

Page 15: Operator overloading II Output, input and other operators.

Overloading ++ and --

It makes a big difference whether you are overloading the prefix (++i) or the postfix (i++) versions of this operator.

Prefix makes the change, then processes the variable.

Postfix processes the variable, then makes the change.

Page 16: Operator overloading II Output, input and other operators.

Overloaded prefix ++Class Inventory{ private: int stockNum; int numSold; public: Inventory(const int stknum, const int sold); friend ostream& out, const Inventory& item); Inventory* operator++();}

Inventory& Inventory::operator++(){ ++numsold; // or ++this->numsold; return(*this);}

Page 17: Operator overloading II Output, input and other operators.

Use of the prefix ++

Inventory someItem(789, 84);// the stockNum is 789// the numSold is 84

++someItem;

cout << someItem; // output says 85 items sold

Page 18: Operator overloading II Output, input and other operators.

Problem

The definition of the prefix operator is easy enough. It increments the value before any other operation.

But how will C++ be able to tell the difference between a prefix ++ operator and a postfix ++ operator

Answer: overloaded postfix operators take a dummy argument.

Page 19: Operator overloading II Output, input and other operators.

Postfix operatorInventory& Inventory::operator++() // prefix version{ ++numsold; // or ++this->numsold; return(*this);}

Inventory& Inventory::operator++(int) // postfix version{ numsold++; // or this->numsold++; return(*this);}

dummy argument

Page 20: Operator overloading II Output, input and other operators.

Example of member functions for Fraction class

// the prototype in the class definitionFraction& operator++(); // prefixFraction& operator++(int); // postfix

Fraction& Fraction::operator++(){ numerator = numerator + denominator; return(*this);}Fraction& Fraction::operator++(int n){ numerator = numerator + denominator; return(*this);}

Page 21: Operator overloading II Output, input and other operators.

Overloading relational operators (==)

// the prototype in the class definitionint operator==(Fraction const& f2);

int Fraction::operator==(Fraction& f2){ if (numerator == f2.numerator && denominator == f2.denominator) return(1); else return(0);}

Page 22: Operator overloading II Output, input and other operators.

Assignment operator=

Similar to the copy constructor, butRe-initializes already constructed objects

Date today; // copy constructor

...

today = “9/20/1999”;

Need assignment operator accepting char*

Page 23: Operator overloading II Output, input and other operators.

Assignment operator

Class Date {

Date& operator=(const char* dCptr);

...

}

Date::operator=(const char* dCptr) {

// parse dateCptr into m, d, y

assign(m, d, y);

}

Page 24: Operator overloading II Output, input and other operators.

Assignment operator

Compiler generates a default assignment operator if you do not define one bitwise copy only (‘shallow copy’)

If you have dynamically allocated memory in your objects then you will need to write an assignment operator to create ‘deep copies’

Page 25: Operator overloading II Output, input and other operators.

Assignment operator

Bitwise copy ok for classes like Date members of simple types only no pointers, therefore no remote

ownership

What happens if we bitwise copy an object owning a resource? Same problem as with default copy

constructors

Page 26: Operator overloading II Output, input and other operators.

Assignment Declaration

class Set {

public:

//Constructors...

Set& operator=(const Set &s);

private:

int *data;

int size;

};

Page 27: Operator overloading II Output, input and other operators.

Set& Set::operator=(const Set &s)

{

if (this != &s) // no assignment to self

{

if (data != 0)

delete [] data;

size = s.size;

data = new int[size];

for (int i=0; i<size; ++i)

data[i] = s.data[i];

}

return *this;

}

Page 28: Operator overloading II Output, input and other operators.

Overloading restrictionsAt least one of the arguments to an

overloaded operator MUST be an instance of the class to which the operator belongs.

Class Date{ public: // member functions

Date operator+(const Date&); // OK!Date operator+(); // OK, due to ‘this’

};// non-member functionsfriend Date operator+(int, int); // ERROR, no Datesfriend Date operator-(int, const Date&); // OK

Page 29: Operator overloading II Output, input and other operators.

Overloading unary operators

If the unary operator is a member function, then Empty argument list (no explicit arguments) Single argument passed implicitly (this)

If the unary operator is not a member function than there will be one argument

Page 30: Operator overloading II Output, input and other operators.

Subscript operator[]

Defines array style syntax for accessing individual elements of “container” classes Usage examples

Set s1;s1[0] = 5;int value = s1[0];

MUST be made a class member

Implementation Example

Page 31: Operator overloading II Output, input and other operators.

class Set {

public:

//Constructors...

int& operator[](const int index);

private:

int *data;

int size;

};

Page 32: Operator overloading II Output, input and other operators.

int& Set::operator[](const int index)

{

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

return data[0];

return data[index];

}

Page 33: Operator overloading II Output, input and other operators.

class Set {

public:

//Constructors…

int& operator[](const int index);

private:

friend ostream& operator<<(ostream &stream, const Set &s);

};

Page 34: Operator overloading II Output, input and other operators.

ostream& operator<<(ostream &stream, const Set &s)

{

for (int i=0; i<s.size(); ++i)

stream << s[i] << “ “;

stream << endl;

return stream;

}

Page 35: Operator overloading II Output, input and other operators.

Const Version of operator[]

Must also add a const version of []

Back to class definitionint operator[](const int size) const

Page 36: Operator overloading II Output, input and other operators.

class Set {

public:

//Constructors...

int& operator[](const int index);

int operator[](const int index) const;

private:

int *data;

int size;

};

Page 37: Operator overloading II Output, input and other operators.

Operator[] Summary

non-const object const object

Set s; const Set s;

assignment retrieval assignment retrievals[0] = 5; cout << s[0]; s[0] = 5; cout << s[0];

non-const version of [] const version of []may need lvalue, must return reference does not need lvalue -> no

reference

Page 38: Operator overloading II Output, input and other operators.

Operators - Global or Member ?

Choice impacts the usage of the type Decision based on how you think type will be

used

Addition (Operator+) for Set Operator+ for sets creates union of both

arguments Assume we made it a member function

Page 39: Operator overloading II Output, input and other operators.

Addition (Operator+) Example

Example:Set s1, s2, s3;

s3 = s1 + s2;

s3 = s1 + 2;

s3 = 2 + s1;

Why not create a constructor that takes an integer as an argument. Then it would be implicitly converted and the + operator could be called.

Good idea, but won’t work as a general rule ! Why not ? 2 = s1; // would then become legal

Page 40: Operator overloading II Output, input and other operators.

Better Solution - Global

Make addition (operator+) a global function How many global operator functions needed ?

Capture s1 + s2, s1 + 2, 2 + s1For each global operator function, add the friend

specifier to the class declaration

How could I reduce it to 1 global op. function?Now use an implicit conversion !C++ implicitly converts lhs arguments ONLY when it

applies to a global operator function, NOT member functions, thus can do 2 + s1, not 2 = s1

Page 41: Operator overloading II Output, input and other operators.

Operators - Rules of thunb

Member operator functions Ones that are required to be members

([]) Generally have a “=“ in them

Global operators Generally, +, -, /, *

Decision based on use !

Page 42: Operator overloading II Output, input and other operators.

Constructors as type conversions

What is a constructor is passed a value it does not expect? It may promote it.

MyType::MyType(AnotherType);

MyType::MyType(const AnotherType&);

implicitly convert AnotherType object into MyType object

Page 43: Operator overloading II Output, input and other operators.

Constructors as type conversions

If an object of MyType is expected, but object of AnotherType is specified

class string { string(int len); … };

string s1(“C”), s2(“++”);

cout << s1 + 10 + s2;

// equivalent to:

cout << s1 + tempString(10) + s2;