Presentation is loading. Please wait.

Presentation is loading. Please wait.

Operator overloading II

Similar presentations


Presentation on theme: "Operator overloading II"— Presentation transcript:

1 Operator overloading II
Output, input and other operators

2 ‘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

3 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

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

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

6 operator<< overloading
ostream& 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.

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

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

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

10 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.

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

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

13 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.

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

15 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.

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

17 Use of the prefix ++ Inventory someItem(789, 84);
// the stockNum is 789 // the numSold is 84 ++someItem; cout << someItem; // output says 85 items sold

18 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.

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

20 Example of member functions for Fraction class
// the prototype in the class definition Fraction& operator++(); // prefix Fraction& operator++(int); // postfix Fraction& Fraction::operator++() { numerator = numerator + denominator; return(*this); } Fraction& Fraction::operator++(int n)

21 Overloading relational operators (==)
// the prototype in the class definition int operator==(Fraction const& f2); int Fraction::operator==(Fraction& f2) { if (numerator == f2.numerator && denominator == f2.denominator) return(1); else return(0); }

22 Assignment operator= Similar to the copy constructor, but
Re-initializes already constructed objects Date today; // copy constructor ... today = “9/20/1999”; Need assignment operator accepting char*

23 Assignment operator Class Date { Date& operator=(const char* dCptr);
... } Date::operator=(const char* dCptr) { // parse dateCptr into m, d, y assign(m, d, y);

24 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’

25 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

26 Assignment Declaration
class Set { public: //Constructors... Set& operator=(const Set &s); private: int *data; int size; };

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

28 Overloading restrictions
At 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 functions friend Date operator+(int, int); // ERROR, no Dates friend Date operator-(int, const Date&); // OK

29 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

30 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

31 class Set { public: //Constructors... int& operator[](const int index); private: int *data; int size; };

32 int& Set::operator[](const int index)
{ if (index < 0 || index >= size) return data[0]; return data[index]; }

33 class Set { public: //Constructors… int& operator[](const int index); private: friend ostream& operator<<(ostream &stream, const Set &s); };

34 ostream& operator<<(ostream &stream, const Set &s)
{ for (int i=0; i<s.size(); ++i) stream << s[i] << “ “; stream << endl; return stream; }

35 Const Version of operator[]
Must also add a const version of [] Back to class definition int operator[](const int size) const

36 class Set { public: //Constructors... int& operator[](const int index); int operator[](const int index) const; private: int *data; int size; };

37 Operator[] Summary non-const object const object Set s; const Set s;
assignment retrieval assignment retrieval s[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

38 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

39 Addition (Operator+) 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

40 Better Solution - Global
Make addition (operator+) a global function How many global operator functions needed ? Capture s1 + s2, s1 + 2, 2 + s1 For 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

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

42 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

43 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 << s s2; // equivalent to: cout << s1 + tempString(10) + s2;


Download ppt "Operator overloading II"

Similar presentations


Ads by Google