operator overloading ii output, input and other operators

43
Operator overloading II Output, input and other operators

Upload: quentin-mclaughlin

Post on 02-Jan-2016

243 views

Category:

Documents


1 download

TRANSCRIPT

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

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

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

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

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.

Advantages

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

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?

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)

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.

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

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}

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.

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;

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.

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

Use of the prefix ++

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

++someItem;

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

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.

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

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

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

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*

Assignment operator

Class Date {

Date& operator=(const char* dCptr);

...

}

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

// parse dateCptr into m, d, y

assign(m, d, y);

}

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’

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

Assignment Declaration

class Set {

public:

//Constructors...

Set& operator=(const Set &s);

private:

int *data;

int size;

};

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;

}

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

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

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

class Set {

public:

//Constructors...

int& operator[](const int index);

private:

int *data;

int size;

};

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

{

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

return data[0];

return data[index];

}

class Set {

public:

//Constructors…

int& operator[](const int index);

private:

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

};

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

{

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

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

stream << endl;

return stream;

}

Const Version of operator[]

Must also add a const version of []

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

class Set {

public:

//Constructors...

int& operator[](const int index);

int operator[](const int index) const;

private:

int *data;

int size;

};

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

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

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

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

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 !

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

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;