1 / 72

Overloading

Functions overloading Operator overloading. Overloading. Function overloading. 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

azra
Download Presentation

Overloading

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. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Functions overloading • Operator overloading Overloading

  2. Function 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

  4. overload.cpp (1/2) // function square for int values int square(int x) { cout << "square of integer " << x << " is "; return x * x; } // end function square with int argument // function square for double values double square(double y) { cout << "square of double " << y << " is "; return y * y; } // end function square with double argument Defining a square function for ints and doubles

  5. overload.cpp (2/2) 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 49 square of double 7.5 is 56.25 • Sample Output • Output confirms that the proper function was called in each case

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

  7. Function Overloading • How the compiler differentiates overloaded functions: • Overloaded functions are distinguished by their signatures • Compiler 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

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

  9. Motivation Class 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 function c=add(a,b); // non-member (global) function … } Or Rational add(Rational) {…}; Ideally  c = a + b;

  10. Operator Overloading: a syntax sugar! ‘+’ is a function (operator function), is called ‘operator+’, and can be overloaded! 2+3 is operator+(2,3) ‘a+b’ is ‘operator+(a,b)’ or ‘a.operator+(b)’ a member function a (global) non-member function

  11. ‘addition operator’ of two Rational numbers obj1.add(obj2)  obj1 + obj2 Class Rational { public: … Rational operator+(const Rational&) { … return Rational(…); }; … } main() { Rational a,b,c; c=a+b; … } The form of a+b is translated into a.operator+(b)

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

  13. Use a non-member function 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. Class 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; … }

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

  15. Overloading the assignment operator =

  16. Assignment Operator ‘=‘ A a,b; a = b; • 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

  17. class T { ... public: ... void operator=(const T&); ... }; void T::operator=(const T& right) { … } main() { T a,b; … a = b; // a.operator=(b) … } it can NOT be a const function, as ‘=‘ modifies the object OK for a = b, But not for the chaining of assignments: a = b = c = … a.operator=(b.operator=(c)) It should be an object here …

  18. A function returning an object 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!)

  19. A function returning a constant object ? const X f() { X x; return x; } It’s the same, but enforces that it cannot be a left value

  20. Put ‘const’ everywhere, three different places 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; … }

  21. Excercises: class X { public: X() {cout << "constructor\n";} X(const X& x){cout << "copy constructor\n"; } }; // return an object of X X f() { X x; return x; } // must be rvalue const 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 }

  22. A constructor is called when: • declare/define objects • pass by value • return by value X f(X x) { X a; return a; }

  23. Object references We have pointers to class objects (low-level manipulations) ap->getx(); (*ap).getx(); delete ap; class A { public: getx(); private: int x; } Access and deletion We also have references to objects int i; int& j = i; A a; A& b=a;

  24. A function returning an object 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); } 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; } No! b disappears No! a disappears OK! but the referenced object should exisit!

  25. 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’! ‘references’ to local variables are not possible! The object have to exist after the function! ‘return by constant reference’ means that the object being returned cannot itself be modified later on!

  26. class X { public: X() {cout << "constructor\n";} X(const X& x){cout << "copy constructor\n"; } }; // return an object of X X f() { X x; return x; } // must be rvalue const X cf() { X x; return x; } // must be rvalue const X& crf(X& x){ return x; } //can be rvalue or lvalue X& rf(X& x){ return x; } 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; } 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)

  27. Object self-reference: the ‘this’ pointer Every class has a keyword, ‘this’, which is a pointer to the object itself. Thus, *this is the object itself! Class Object Function members A& F::f(){ // … return *this; } *this Data members this Can return the modified object. int i; int& j = i;

  28. Returning a reference or a const reference? a = b = c always means a = (b = c) as ‘=‘ is right associative, it is a r-value. 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

  29. It can be both a l-value and r-value! 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&);

  30. class T { ... public: ... T& operator=(const T&); ... }; T& T::operator=(const T& right) { … return *this; } main() { T a,b; … b = a; // b.operator=(a) … } it can NOT be a const function, as ‘=‘ modifies the object *this refers to the calling object Returning a reference allows the chaining of operators a = b = c = d;  a = (b = (c = d))  a.operator=(b.operator=(c.operator=(d)))

  31. 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) … } Summary on ‘=‘ overloading 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

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

  33. Overloading input/output streams

  34. Input/output class 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.

  35. ‘Rational’ example void Rational::Display() const { cout << Numerator << '/' << Denominator; } Example t.Display(); ostream& operator<<(ostream& out, const Rational t) { out << Numerator << '/' << Denominator; return out; } Example cout << t; ofstream fout(“toto”); fout.open(…); fcout << t;

  36. void Rational::Get() { char slash; cin >> Numerator >> slash >> Denominator; if(Denominator == 0){ cout << "Illegal denominator of zero, " << "using 1 instead" << endl; Denominator = 1; } } Example t.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; } Example cin >> t;

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

  38. Essential operators class X { X(); X(const X&); ~X(); X& operator=(const X&); … } ostream& operator<<(ostream& out, const X x) { … }

  39. 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& private a,b; // error: operator, private }

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

  41. Operator overloading: part II

  42. 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 operands • e.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 +=

  43. 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;

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

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

  46. Commutative Operators for global functions HugeInt operator+( long, HugeInt ); // function overloading HugeInt operator+( HugeInt, long ); HugeInt operator+( HugeInt, HugeInt ); • 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

  47. 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., !fbecomes operator!(f)

  48. Overloading Binary Operators int i=2,j=4; (j +=i) += 2; // return the new j cout << i << j; // output 2 8 • 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:

  49. Overloading subscription operators

  50. 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 …

More Related