1 Overloading Functions overloading Operator overloading.

73
1 Overloading Functions overloading Operator overloading

description

3 Function Overloading  Overloaded functions have Same name Different sets of parameters  Compiler selects proper function to execute based on number, types and order of arguments in the function call  Commonly used to create several functions of the same name that perform similar tasks, but on different data types and numbers of parameters

Transcript of 1 Overloading Functions overloading Operator overloading.

Page 1: 1 Overloading  Functions overloading  Operator overloading.

1

Overloading

Functions overloading Operator overloading

Page 2: 1 Overloading  Functions overloading  Operator overloading.

2

Function overloading

Page 3: 1 Overloading  Functions overloading  Operator overloading.

3

Function Overloading Overloaded functions have

• Same name• Different sets of parameters

Compiler selects proper function to execute based on number, types and order of arguments in the function call

Commonly used to create several functions of the same name that perform similar tasks, but on different data types and numbers of parameters

Page 4: 1 Overloading  Functions overloading  Operator overloading.

4

overload.cpp (1/2)

Defining a square function for ints and doubles

// function square for int valuesint square(int x){ cout << "square of integer " << x << " is "; return x * x; } // end function square with int argument

// function square for double valuesdouble square(double y) { cout << "square of double " << y << " is "; return y * y; } // end function square with double argument

Page 5: 1 Overloading  Functions overloading  Operator overloading.

5

overload.cpp (2/2)

Sample Output

Output confirms that the proper function was called in each case

int main(){ cout << square( 7 ); // calls int version cout << endl; cout << square( 7.5 ); // calls double version cout << endl; return 0; // indicates successful termination} // end main

square of integer 7 is 49square of double 7.5 is 56.25

Page 6: 1 Overloading  Functions overloading  Operator overloading.

6

More examples ...

#include <stdio.h>

int max(int a, int b) { if (a > b) return a; return b;}

char* max(char* a, char* b) { if (strcmp(a, b) > 0) return a; return b;}

int main() { cout << “max(19, 69) = “ << max(19, 69) << endl; cout << “max(“abc”, “def”) = “ << max(“abc”, “def”) << endl;

}

Page 7: 1 Overloading  Functions overloading  Operator overloading.

7

Function Overloading How the compiler differentiates overloaded functions:

• Overloaded functions are distinguished by their signaturesCompiler encodes each function identifier with the number and types of

its parameters to enable type-safe linkage • Type-safe linkage ensures that

Proper overloaded function is called Types of the arguments conform to types of the parameters

Creating overloaded functions with identical parameter lists and different return types is a compilation error• It is ambiguous on which function to call

Page 8: 1 Overloading  Functions overloading  Operator overloading.

8

Operator overloading: part I (good for users, hard for developpers )

Page 9: 1 Overloading  Functions overloading  Operator overloading.

9

MotivationClass Rational {public:

Rational(int, int) const;…Rational add(const Rational&) {…return (Rational(…));};…

private:int numerator;int denumerator;

}Rational add(const Rational& c1, const Rational& c2) {

…return Rational(…,…);

}

main() {Rational a,b,c;c=a.add(b); // member functionc=add(a,b); // non-member (global) function…

}

Ideally c = a + b;

Or Rational add(Rational) {…};

Page 10: 1 Overloading  Functions overloading  Operator overloading.

10

Operator Overloading: a syntax sugar!

‘+’ is a function (operator function),is called ‘operator+’,

and can be overloaded!

‘a+b’ is ‘operator+(a,b)’ or ‘a.operator+(b)’

a (global) non-member function

a member function

2+3 is

operator+(2,3)

Page 11: 1 Overloading  Functions overloading  Operator overloading.

11

‘addition operator’ of two Rational numbers

obj1.add(obj2) obj1 + obj2

The form of a+b is translated into a.operator+(b)

Class Rational {public:…

Rational operator+(const Rational&) {…return Rational(…);

};…

}

main() {Rational a,b,c;c=a+b;…

}

Page 12: 1 Overloading  Functions overloading  Operator overloading.

12

But,

‘a+b+c’ is fine: a.operator+(b.operator+(c)) ‘a+10’ is fine (if we modify it ): a.operator+(10)

Rational operator+(const int i) { …} How about ‘10+a’ ? 10.operator+(a)?

Page 13: 1 Overloading  Functions overloading  Operator overloading.

13

Use a non-member functionClass Rational {public:

…int numerator();int denumerator();…Rational operator+(const Rational&);Rational operator+(const int);…

}Rational operator+(const int num1, const Rational& r2) {

…return Rational(numerator(…),denumerator(…));

}

main() {Rational a,b,c;c=10+a;c=a+10;…

} A call of a+b is then converted to operator+

(a,b) 10+a operator+(10,a) (a normal function

call, not a ‘method’ of an object)

If the first operand (or the left operand) is not an object of the same class, we cannot use a ‘member function’, so have to use a normal overloaded function.

Page 14: 1 Overloading  Functions overloading  Operator overloading.

14

‘Friend’ is coming to help … We can define (global) functions or classes to be friends

of a class to allow them direct access to its private data members

Class Rational { ... public: ... friend Rational operator+(const Rational&, const Rational&); };

Rational operator+(const Rational& op1, const Rational& op2) { int numerator = op1.numerator*op2.denumerator + op2.numerator*op1.denumerator;

int denumerator = op1.denumerator*op2.denumerator; return(Rational(numerator,denumberator)); }

Access to private data thanks to the ‘friendship’!

No ‘friend’, we need to do: op1.numerator();

Page 15: 1 Overloading  Functions overloading  Operator overloading.

15

Overloading the assignment operator =

Page 16: 1 Overloading  Functions overloading  Operator overloading.

16

Assignment Operator ‘=‘

Assignment operator (=) can be used to assign an object to another object of the same type• Member-wise assignment: each data member of the right object is

assigned to the same data member in the left object

A a,b;a = b;

Page 17: 1 Overloading  Functions overloading  Operator overloading.

17

class T { ... public: ... void operator=(const T&);

...};

void T::operator=(const T& right) {…

}

main() {

T a,b; …a = b; // a.operator=(b)…

}

OK for a = b, But not for the chaining of assignments: a = b = c = …

a.operator=(b.operator=(c))

it can NOT be a const function, as ‘=‘ modifies the object

It should be an object here …

Page 18: 1 Overloading  Functions overloading  Operator overloading.

18

X f() { X x; return x;}

‘return x’ returns a temporay object ‘temp’ of class X by constructor (because x is a local object, and to be lost!)

A function returning an object

Page 19: 1 Overloading  Functions overloading  Operator overloading.

19

const X f() { X x; return x;}

It’s the same, but enforces that it cannot be a left value

A function returning a constant object ?

Page 20: 1 Overloading  Functions overloading  Operator overloading.

20

Class Rational {public:

…const Rational operator+(const Rational& r2) const;const Rational operator+(const int num2) const;…

}

main() {Rational a,b,c;c=a+10;…

}

Put ‘const’ everywhere, three different places

Page 21: 1 Overloading  Functions overloading  Operator overloading.

21

class X {public: X() {cout << "constructor\n";} X(const X& x){cout << "copy constructor\n"; }};

// return an object of XX f() { X x; return x;}

// must be rvalueconst X cf() { X x; return x;}

constructor (for X x in main)constructor (for X y in main)

constructor (for X x in f)copy constructor (Unix has that, but not Linux, for return x in f)

constructor (for X x in cf)copy constructor (Unix has that, but not Linux, for return x in cf)

int main() { X x,y;

f() = x; // No compilation error but does nothing

f = cf(); // cfx() = x is error }

Excercises:

Page 22: 1 Overloading  Functions overloading  Operator overloading.

22

X f(X x) { X a; return a;}

A constructor is called when: declare/define objects pass by value return by value

Page 23: 1 Overloading  Functions overloading  Operator overloading.

23

X& f() {

}

A function returning a reference ?

Page 24: 1 Overloading  Functions overloading  Operator overloading.

24

Object references

class A {public:

getx();private:

int x;}

ap->getx();(*ap).getx();

delete ap;

A a;A& b=a;

Access and deletion

We have pointers to class objects (low-level manipulations)

int i;int& j = i;

We also have references to objects

Page 25: 1 Overloading  Functions overloading  Operator overloading.

25

class A {public:

A& f(A a);private:

int x;}

A& A::f(A a) {A b;…return b;

}A& A::f(A a) {

…return a;

}A& A::f(A& a) {

A b;…return a;

}

returning a reference

class A {public:

A f(A a);private:

int x;}

A A::f(A a) {A b;…return b;

}

main() {A a,b,c;c = a.f(b);}

A function returning an object

but the referenced object should exisit!

No! b disappears

No! a disappears

OK!

Page 26: 1 Overloading  Functions overloading  Operator overloading.

26

class A {public:

A& f(A a);private:

int x;}

const A& A::f(const A& a) {…return a;

}

‘return by value’ is safe. Avoid ‘return by reference’.If we want to avoid the copy, we ‘return by constant reference’!

‘return by constant reference’ means that the object being returned cannot itself be modified later on!

‘references’ to local variables are not possible! The object have to exist after the function!

Page 27: 1 Overloading  Functions overloading  Operator overloading.

27

class X {public: X() {cout << "constructor\n";} X(const X& x){cout << "copy constructor\n"; }};

// return an object of XX f() { X x; return x;}

// must be rvalueconst X cf() { X x; return x;}

// must be rvalueconst X& crf(X& x){ return x;}

//can be rvalue or lvalueX& rf(X& x){ return x; }

constructor (for X x in main)constructor (for X y in main)

constructor (for X x in f)copy constructor (Unix has that, but not Linux, for return x in f)

constructor (for X x in cf)copy constructor (Unix has that, but not Linux, for return x in cf)

int main() { X x,y;

f() = x; // No compilation error but does nothing

f = cf(); // cfx() = x is error f = rf( y );

f = crf( y ); // crfx( y ) = x is error return 0;}

Page 28: 1 Overloading  Functions overloading  Operator overloading.

28

Object self-reference: the ‘this’ pointer

Function members

Data members

Class Object

this

*this

Every class has a keyword, ‘this’, which is a pointer to the object itself. Thus, *this is the object itself!

A& F::f(){ // … return *this;}

Can return the modified object.int i;int& j = i;

Page 29: 1 Overloading  Functions overloading  Operator overloading.

29

Returning a reference or a const reference?

a = b = c always means a = (b = c) as ‘=‘ is right associative, it is a r-value.

r-value, appear on the right side of assignment, ‘readable’l-value, on the left side, ‘writable’

We can write (a=b)=c, depending on what a=b returns.

int i=5, j=4;

(i=j)=3; // lvalue, return the new i cout << i<< j ; // get 3 4

(i=3)=4; // lvalue, return the new i cout << i<< j ; // get 4 4

i = j = 3; // get 3 3

Page 30: 1 Overloading  Functions overloading  Operator overloading.

30

We cannot write (a = b) = c if we return a const ref:const T& operator=(const T&);

We can do (a=b)=c if we return a non-constant ref: T& operator=(const T&);

It can be both a l-value and r-value!

Page 31: 1 Overloading  Functions overloading  Operator overloading.

31

class T { ... public: ... T& operator=(const T&);

...};

T& T::operator=(const T& right) {…return *this;

}

main() {

T a,b; …b = a; // b.operator=(a)…

}

*this refers to the calling object

Returning a reference allows the chaining of operatorsa = b = c = d; a = (b = (c = d)) a.operator=(b.operator=(c.operator=(d)))

it can NOT be a const function, as ‘=‘ modifies the object

Page 32: 1 Overloading  Functions overloading  Operator overloading.

32

class T { ... public: ... T& operator=(const T& right);

...};

T& T::operator=(const T& right) {if (this == &right) return *this;…return *this;

}

main() {

T a,b; …b = a; // b.operator=(a)…

}

1. Const reference for the argument (a r-value)

2. Return a reference to the left-hand side (a l-value), and *this is converted into a reference

3. Check for self-assignment

Summary on ‘=‘ overloading

Page 33: 1 Overloading  Functions overloading  Operator overloading.

33

Other operators such as+=,-=,*=, …can be overloaded in a similar manner.

Page 34: 1 Overloading  Functions overloading  Operator overloading.

34

Overloading input/output streams

Page 35: 1 Overloading  Functions overloading  Operator overloading.

35

Input/outputclass T { ...};

ostream& operator<<(ostream& out, const T t) {…return out;

}

istream& operator>>(istream& in, T& t) {…return in;

}

main() {

T a;…cin >> a;cout << a;…

} Before, we wrote a ‘display’ or ‘print’ function.

Page 36: 1 Overloading  Functions overloading  Operator overloading.

‘Rational’ examplevoid Rational::Display() const {

cout << Numerator << '/' << Denominator;}

Examplet.Display();

ostream& operator<<(ostream& out, const Rational t) { out << Numerator << '/' << Denominator;return out;

}

Example cout << t;

ofstream fout(“toto”); fout.open(…); fcout << t;

Page 37: 1 Overloading  Functions overloading  Operator overloading.

void Rational::Get() {char slash;cin >> Numerator >> slash >> Denominator;if(Denominator == 0){ cout << "Illegal denominator of zero, "

<< "using 1 instead" << endl; Denominator = 1;}

}

Examplet.Get();

istream& operator>>(istream& in, T& t) {char slash;in >> Numerator >> slash >> Denominator;if(Denominator == 0){

cout << "Illegal denominator of zero, " << "using 1 instead" << endl;

Denominator = 1;}

return in;}

Examplecin >> t;

Page 38: 1 Overloading  Functions overloading  Operator overloading.

38

Which operators to overload? Only those for which it makes sense … … and for which there is a genuine need … … and which the users will expect Typically these are usually appropriate:

= << >>

If the class involves ‘arithmetic type’ (e.g. complex, rational, vector, matrix, …), arithmetic operations should be provided.

Page 39: 1 Overloading  Functions overloading  Operator overloading.

39

Essential operators

class X {X();X(const X&);~X();X& operator=(const X&);

…}

ostream& operator<<(ostream& out, const X x) {…

}

Page 40: 1 Overloading  Functions overloading  Operator overloading.

40

How to ‘hide’ or ‘disable’ an operator?

class X {private:

void operator=(const X&);void operator&();void operator,(const X&);…

}

Void f(X a, X b) {a=b; // error: operator= private&a; // error: operator& privatea,b; // error: operator, private

}

Page 41: 1 Overloading  Functions overloading  Operator overloading.

41

Use a private function to overload others

class Rational {public:

const Rational operator+(Rational r) {return add(…);};const Rational operator+(int i) {return add(…);};const Rational operator+(…) {return add(…);}

private:const Rational add(a,b,c,d) {return Rational(a*d+b*c,b*d);}

}

const Rational operator+(int i, Rational) {return add(…);

} This also gives one example of defin ring a ‘private’ member function.

Page 42: 1 Overloading  Functions overloading  Operator overloading.

42

Operator overloading: part II

Page 43: 1 Overloading  Functions overloading  Operator overloading.

43

Restrictions on Operator Overloading Cannot change

• Precedence of operator (order of evaluation)Use parentheses to force order of operators

• Associativity (left-to-right or right-to-left)2*3*4 (=6*4) vs. 2^3^2 (=2^9)

• Number of operandse.g., !, & or * is unary, i.e., can only act on one operand as in &i or *ptr

• How operators act on built-in/primitive data types (i.e., cannot change integer addition)

Cannot create new operators Operators must be overloaded explicitly

• Overloading + and = does not overload +=

Page 44: 1 Overloading  Functions overloading  Operator overloading.

44

Operators that can be overloaded+ - * / % ^ & |~ ! = < > += -= *=/= %= ^= &= |= << >> >>=

<<= == != <= >= && || ++-- ->* , -> [] () new delete

new[] delete[]

Operators that cannot be overloaded

. .* ? :

Member functions declaration: bool operator!() const; bool operator==(const T&) const; bool operator<(const T&) const; bool operator!=(const T& right) const; bool operator>( const T& right) const; bool operator<=(const T& right) const; bool operator>=(const T& right) const;

Page 45: 1 Overloading  Functions overloading  Operator overloading.

45

Operators as Class Members

Leftmost object must be of the same class as operator function

Use this keyword to explicitly get left operand argument Operators (), [], -> or some other assignment operator

must be overloaded as a class member function Called when

• Left operand of binary operator is of this class• Single operand of unary operator is of this class

Page 46: 1 Overloading  Functions overloading  Operator overloading.

46

Operators as Global Functions

Need parameters for both operands Can have object of different class Can be a friend to access private (or protected) data Both << and >> must be global functions

• Cannot be class members Overloaded << operator

• Left operand is of type ostream&Such as cout object in cout << classObject

Similarly, overloaded >> has left operand of istream&• Such as cin object in cin >> classObject

Page 47: 1 Overloading  Functions overloading  Operator overloading.

47

Commutative Operators for global functions

May want + to be commutative• So both “a + b” and “b + a” work

Suppose we have two different classes• If the overloaded operator is a member function, then its class is on left

HugeIntClass + long int• Can be member function for HugeIntClass

HugeIntClass + HugeIntClass• Can be member function as well

long int + HugeIntClass• For this to work, + needs to be a global overloaded function

HugeInt operator+( long, HugeInt ); // function overloading HugeInt operator+( HugeInt, long ); HugeInt operator+( HugeInt, HugeInt );

Page 48: 1 Overloading  Functions overloading  Operator overloading.

48

Overloading Unary Operators Can overload as member function with no arguments Can overload as global function with one argument

• Argument must be class object or reference to class object If member function, needs no arguments• bool operator!() const;

If global function, needs one argument• bool operator!( const T& ), i.e., !f becomes operator!(f)

Page 49: 1 Overloading  Functions overloading  Operator overloading.

49

Overloading Binary Operators Member function: one argument• const T& operator+=(const T&);• s1 += s2; // a string• s1 += s2 += s3; // same as s1 += ( s2 += s3 );• (s1 += s2) += s3; // compiler yells

Global function: two arguments• One of the arguments must be class object or reference• const T& operator+=(T&, const T&); // no const for the first argument• y += z becomes operator+=( y, z )

Note that int type provides a variant of lvalue:

int i=2,j=4;(j +=i) += 2; // return the new jcout << i << j; // output 2 8

Page 50: 1 Overloading  Functions overloading  Operator overloading.

50

Overloading subscription operators

Page 51: 1 Overloading  Functions overloading  Operator overloading.

51

Subscription Operator ‘[]‘

A a,b;a[3];

For example, we can enable this operator for a list (whether it is array-based or linked):

List l;L[10]

Or we can re-number from 1 instead of 0 …

Page 52: 1 Overloading  Functions overloading  Operator overloading.

52

T& operator[](int);

It returns the object at the given integer index It can be both lvalue and rvalue

T& operator[](int i){ …};

Page 53: 1 Overloading  Functions overloading  Operator overloading.

53

// subscript operator: if you only want it to be an rvalue T operator[](int) const; // constant member function; cannot be lvalue // May also be

// const T& operator[](int) const; // but NOT

// T& operator[](int) const; // (compile error)

The ‘const’ matters, and is part of the prototype,• We call it const overloading (the prototypes above)

The compiler decides based on the type of the calling object. • If it is const object, the const member function will be used.

Sometimes we need this if we want to use a different member function for a const object.

• If it is not a const object, the non-const function will be used, no matter whether it is a rvalue or lvalue

Page 54: 1 Overloading  Functions overloading  Operator overloading.

54

#include <iostream>using namespace std;

class B {public: const int& operator[](int i) const{ cout << "Constant [] function is called" << endl; return data[i]; } int& operator[](int i){ cout << "Non-constant [] function is called" << endl; return data[i]; }private: int data[10];};

int main(){ B b1; const B bc = b1; b1[0]; b1[2] = bc[2]; cout << bc[1] << endl; return 0;}

Non-constant [] function is called (for b1[0])Non-constant [] function is called (for b1[2])Constant [] function is called (for bc[2])Constant [] function is called (for bc[1])0

Page 55: 1 Overloading  Functions overloading  Operator overloading.

55

T operator()(int, int = 0) const; // at most 2 parameters

A a,b;a(3);

A a,b;a(3,1);

Page 56: 1 Overloading  Functions overloading  Operator overloading.

56

Case Study: String Class

Build class String• String creation, manipulation• Similar to class string in standard library

Conversion constructor• Any single-argument constructor• Turns objects of other types into class objects• Example: String s1( "happy" );

Creates a String from a char *

Overloading function call operator String.h, String.cpp, stringtester.cpp

Page 57: 1 Overloading  Functions overloading  Operator overloading.

57

class String {friend ostream &operator<<( ostream &, const String & ); // global I/O functions friend istream &operator>>( istream &, String & ); public:

String( const char * = "" ); // conversion/default constructor String( const String & ); // copy constructor ~String(); // destructor

const String &operator=( const String & ); // assignment operator: s1 = s2 = s3; const String &operator+=( const String & ); // concatenation operator: s1 += s2 += s3;

bool operator!() const; // is String empty? bool operator==( const String & ) const; // test s1 == s2 bool operator<( const String & ) const; // test s1 < s2

// test s1 != s2 bool operator!=( const String &right ) const { return !( *this == right ); } // end function operator!=

// test s1 > s2 bool operator>( const String &right ) const { return right < *this; // use the implemented < operator } // end function operator>

// test s1 <= s2 bool operator<=( const String &right ) const { return !( right < *this ); // use the implemented < operator } // end function operator <=

// test s1 >= s2 bool operator>=( const String &right ) const { return !( *this < right ); // use the implemented < operator } // end function operator>=

char &operator[]( int ); // subscript operator (modifiable lvalue) char operator[]( int ) const; // subscript operator (rvalue)

// return a substring. // s(4, 5) returns the substring including and from s[4] for 5 characters // s(4) returns the right part of the string String operator()( int, int = 0 ) const;

int getLength() const; // return string length private:

int length; // string length (not counting null terminator) char *sPtr; // pointer to start of pointer-based string void setString( const char * ); // utility function

}; // end class String

Page 58: 1 Overloading  Functions overloading  Operator overloading.

58

stringtester.cpp Sample Output (1/3)

Conversion (and default) constructor: happyConversion (and default) constructor: birthdayConversion (and default) constructor:s1 is "happy"; s2 is " birthday"; s3 is ""

The results of comparing s2 and s1:s2 == s1 yields falses2 != s1 yields trues2 > s1 yields falses2 < s1 yields trues2 >= s1 yields falses2 <= s1 yields true

Testing !s3:s3 is empty; assigning s1 to s3;operator= calleds3 is "happy"

s1 += s1 += s2 yields s1 = happy birthdayhappy birthday

Page 59: 1 Overloading  Functions overloading  Operator overloading.

59

stringtester.cpp Sample Output (2/3)

s1 += " to you" yieldsConversion (and default) constructor: to youDestructor: to yous1 = happy birthdayhappy birthday to you

Conversion (and default) constructor: happy birthdayCopy constructor: happy birthdayDestructor: happy birthdayThe substring of s1 starting atlocation 0 for 14 characters, s1(0, 14), is:happy birthday

Destructor: happy birthdayConversion (and default) constructor: appy birthday to youCopy constructor: appy birthday to youDestructor: appy birthday to youThe substring of s1 starting atlocation 15, s1(15), is: appy birthday to you

The constructor and destructor are called

for the temporary String

Page 60: 1 Overloading  Functions overloading  Operator overloading.

60

stringtester.cpp Sample Output (3/3)

Destructor: appy birthday to youCopy constructor: happy birthdayhappy birthday to you

*s4Ptr = happy birthdayhappy birthday to you

Assigning *s4Ptr to *s4Ptroperator= calledAttempted assignment of a String to itself*s4Ptr = happy birthdayhappy birthday to youDestructor: happy birthdayhappy birthday to you

s1 after s1[0] = 'H' and s1[6] = 'B' is: Happy Birthdayhappy birthday to you

Attempt to assign 'd' to s1[30] yields:Destructor: happyDestructor: birthdayDestructor: Happy Birthdayhappy birthday td you

Page 61: 1 Overloading  Functions overloading  Operator overloading.

61

Overloading ++, -- operators

Page 62: 1 Overloading  Functions overloading  Operator overloading.

62

Overloading ++ and --

Increment/decrement operators can be overloaded Prefix increment: ++x Postfix increment: x++

operator++()

operator++(int)

For pointer applications!

Page 63: 1 Overloading  Functions overloading  Operator overloading.

63

Prefix increment Member-function prototype for prefix increment

• Date& operator++(); // return a reference for // successive operation: y=++++x• ++d d.operator++()

Global-function prototype for prefix increment• Date& operator++(Date&);• ++d operator++(d)

class X {public:

X& operator++() {...return *this;}

...;}

X x;++x; d++++x (x.operator++()).operator++()

Page 64: 1 Overloading  Functions overloading  Operator overloading.

64

Postfix Increments Member-function prototype for postfix increment:• T operator++(int); // must be rvalue;• d++ d1.operator++(0)

Global-function prototype for postfix increment• T operator++(T&, int); • d++ operator++(d, 0)

class X {public:

X operator++(int) {X old = *this;...return old;}

...;}X x;x++;

A dummy parameter

d++++ impossible cascating!

int i;i++++; NON!++++i; OK!

Page 65: 1 Overloading  Functions overloading  Operator overloading.

65

Case Study: A Date Class Overloaded increment operator

• Change day, month and year Function to test for leap years Function to determine if a day is last of month Date.h, Date.cpp, datetester.cpp

Page 66: 1 Overloading  Functions overloading  Operator overloading.

66

Date.hclass Date{ friend ostream& operator<<( ostream&, const Date& );public: // default constructor Date( int m = 1, int d = 1, int y = 1900 ); void setDate( int, int, int ); // set month, day, year Date& operator++(); // prefix increment operator, ++Date Date operator++( int ); // postfix increment operator, Date++ const Date& operator+=( int ); // add days, modify object bool leapYear( int ) const; // is date in a leap year? bool endOfMonth( int ) const; // is date at the end of month?private: int month; int day; int year; static const int days[]; // static member variable; array of days per month void helpIncrement(); // utility function incrementing date}; // end class Date

Note the difference between prefix and postfix increment

Page 67: 1 Overloading  Functions overloading  Operator overloading.

67

Date.cpp (1/5)#include "Date.h"

// initialize static member at file scope; one classwide copyconst int Date::days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

// Date constructorDate::Date( int m, int d, int y ) { setDate( m, d, y ); } // end Date constructor

// set month, day and yearvoid Date::setDate( int mm, int dd, int yy ) { month = ( mm >= 1 && mm <= 12 ) ? mm : 1; year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;

// test for a leap year if ( month == 2 && leapYear( year ) ) day = ( dd >= 1 && dd <= 29 ) ? dd : 1; else day = ( dd >= 1 && dd <= days[ month ] ) ? dd : 1;} // end function setDate

Page 68: 1 Overloading  Functions overloading  Operator overloading.

68

Date.cpp (2/5)// overloaded prefix increment operator Date& Date::operator++(){ helpIncrement(); // increment date return *this; // reference return to create an lvalue} // end function operator++

// overloaded postfix increment operator; note that the // dummy integer parameter does not have a parameter nameDate Date::operator++( int ){ Date temp = *this; // hold current state of object helpIncrement();

// return unincremented, saved, temporary object return temp; // value return; not a reference return} // end function operator++

Postfix increment updates object and returns a copy of the original

Do not return a reference to temp, because returning a reference may make the variable a lvalue. Since temp is a local variable, it will be destroyed leading to access error

Page 69: 1 Overloading  Functions overloading  Operator overloading.

69

Date.cpp (3/5)// add specified number of days to dateconst Date& Date::operator+=( int additionalDays ) { for ( int i = 0; i < additionalDays; i++ ) helpIncrement(); return *this; // enables cascading} // end function operator+=

// if the year is a leap year, return true; otherwise, return falsebool Date::leapYear( int testYear ) const { if ( testYear % 400 == 0 || (testYear % 100 != 0 && testYear % 4 == 0) ) return true; // a leap year else return false; // not a leap year} // end function leapYear

// determine whether the day is the last day of the monthbool Date::endOfMonth( int testDay ) const { if ( month == 2 && leapYear( year ) ) return testDay == 29; // last day of Feb. in leap year else return testDay == days[ month ];} // end function endOfMonth

Page 70: 1 Overloading  Functions overloading  Operator overloading.

70

Date.cpp (4/5)// function to help increment the datevoid Date::helpIncrement(){ // day is not end of month if ( !endOfMonth( day ) ) day++; // increment day else if ( month < 12 ) // day is end of month and month < 12 { month++; // increment month day = 1; // first day of new month } // end if else // last day of year { year++; // increment year month = 1; // first month of new year day = 1; // first day of new month } // end else} // end function helpIncrement

Page 71: 1 Overloading  Functions overloading  Operator overloading.

71

Date.cpp (5/5)// overloaded output operatorostream& operator<<( ostream& output, const Date& d ){ static char* monthName[ 13 ] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; output << monthName[ d.month ] << ' ' << d.day << ", " << d.year; return output; // enables cascading} // end function operator<<

Page 72: 1 Overloading  Functions overloading  Operator overloading.

72

datetester.cppDate d1; // defaults to January 1, 1900Date d2( 12, 27, 1992 ); // December 27, 1992Date d3( 0, 99, 8045 ); // invalid date

cout << "d1 is " << d1 << "\nd2 is " << d2 << "\nd3 is " << d3;cout << "\n\nd2 += 7 is " << ( d2 += 7 );

d3.setDate( 2, 28, 1992 );cout << "\n\n d3 is " << d3;cout << "\n++d3 is " << ++d3 << " (leap year allows 29th)";

Date d4( 7, 13, 2002 );cout << "\n\nTesting the prefix increment operator:\n“ << " d4 is " << d4 << endl;cout << "++d4 is " << ++d4 << endl;cout << " d4 is " << d4;cout << "\n\nTesting the postfix increment operator:\n“ << " d4 is " << d4 << endl;cout << "d4++ is " << d4++ << endl;cout << " d4 is " << d4 << endl;

Demonstrate prefix increment

Demonstrate postfix increment

Page 73: 1 Overloading  Functions overloading  Operator overloading.

73

datetester.cpp Sample Outputd1 is January 1, 1900d2 is December 27, 1992d3 is January 1, 1900 d2 += 7 is January 3, 1993 d3 is February 28, 1992++d3 is February 29, 1992 (leap year allows 29th) Testing the prefix increment operator: d4 is July 13, 2002++d4 is July 14, 2002 d4 is July 14, 2002 Testing the postfix increment operator: d4 is July 14, 2002d4++ is July 14, 2002 d4 is July 15, 2002