250 likes | 276 Views
Department of Computer and Information Science, School of Science, IUPUI. Operator Overloading. Dale Roberts, Lecturer Computer Science, IUPUI E-mail: droberts@cs.iupui.edu. Operator Overloading.
E N D
Department of Computer and Information Science,School of Science, IUPUI Operator Overloading Dale Roberts, Lecturer Computer Science, IUPUI E-mail: droberts@cs.iupui.edu
Operator Overloading • Function-call notation is cumbersome for certain kinds of classes, especially mathematical classes • Allows extendable design • Most appropriate for math classes. eg. Matrix, Vector, etc. • Gives Operators Class-Specific Functionality • In-built or Standard Overloading for Basic Numerical Data Types -- + can be used with int, float, doubles • Analogous to Function Overloading -- operator@ is Used as the Function Name • 40 Operators can be Overloaded to Give Class-Specific Functionality • C++ enables programmers to overload operators to be sensitive to the context in which they are used. The compiler generates appropriate code • Easier to read
Requirements of Overloaded Operators • Their Meaning Should be Intuitive -- + Should Mean Addition • When Appropriate, they Should be Associative -- a + b Should Result in an Object, c of the Same Class • If these Conditions are Not Satisfied then it is Better to Use Member Functions and Not Operator Overloading • To use an operator on class objects, that operator must be overloaded - with two exceptions - the assignment operator (=), which performs a member wise copy, and the address (&) operator
Forms of Overloaded Operators • Member Functions • Friend Functions • Free-Standing or Global Functions
Operator Functions • When to make class members, friends or global functions? • If member function, then this is implicitly available for one of the arguments • When overloading ( ), [ ], ->, or =, the operator overloading function must be declared as a class member. For other operators, the overloading functions can be non-members • When an operator function is implemented as a member function, the left most (or only in the case of unary operators) operand must be a class object (or a reference to a class object) of operator's class • If the left operand must be an object of a different class or a built-in type, this operator must be implemented as a non-class member. eg. <<, >> operators
Operator Functions (cont) • An operator function implemented as a non-member must be a friend if it needs to access non-public data members of that class. • The overloaded << operator must have a left operand of type ostream. Therefore, it must be a non-member function. Also, it may require access to the private data members of the class. Thus, it needs to be a friend function for that class. • Similar observation holds for >> operator which has a left operand of type istream. • Operator member functions are classed only when the left operand of a binary operator is specifically an object of that class or when the single operand of a unary operator is an object of that class. • If the operator needs to be commutative (a + b = b + a), then making it a non-member function is necessary.
Restrictions of Overloaded Operators • New Operators CANNOT be Created • Fundamental Data Types (e.g. int) CANNOT be Overloaded • Operator Priority CANNOT be Changed • Operator Associativity CANNOT be Changed • The arity of CANNOT be changed -- + can Take ONLY One or TWO Arguments • Two Separate Overloaded Functions (With Different Signatures) can be Created for Operators Which Exist in Pre-fix and Post-fix Form -- ++ • Overloaded Operators are NOT IMPLICITLY Associative or Commutative, Even if the Original Operators were Associative or Commutative -- Associativity and Commutativity must be explicitly implemented. For Associativity this means returning an instance of the class. • Overloading the operator + does not automatically overload related operators (+=, ++, etc). If needed, these related operators must be explicitly overloaded
Unary Overloaded Operators -- Member Functions • Invocation in Two Ways -- Object@ (Direct) or Object.operator@() (As a Function) class number{ int n; public: number(int x = 0):n(x){}; number operator-(){return number (-n);} }; main() { number a(1), b(2), c, d; //Invocation of "-" Operator -- direct d = -b; //d.n = -2 //Invocation of "-" Operator -- Function c = a.operator-(); //c.n = -1 }
Binary Overloaded Operators -- Member Functions • Invocation in Two Ways -- ObjectA @ ObjectB (direct) or ObjectA.operator@(ObjectB) (As a Function) class number{ int n; public: number(int x = 0):n(x){}; number operator+(number ip) {return number (ip.n + n);} }; main() { number a(1), b(2), c, d; //Invocation of "+" Operator -- direct d = a + b; //d.n = 3 //Invocation of "+" Operator -- Function c = d.operator+(b); //c.n = d.n + b.n = 5 }
Operator Overloading Using a Friend Function • Number of Parameters Accepted by an Overloaded Friend Operator Function Depend Upon the Operator Type -- One for Unary Operators and Two for Binary Operators class complex{ int re, im; public: complex(int ip1 = 0, int ip2 = 0) :re(ip1), im(ip2){} friend complex operator+(complex, complex); }; //Friend Operator + Function complex operator+(complex a, complex b) {return complex(a.re+b.re, a.im+b.im);} main(){ complex one(1,1), two(2,2), three; three = operator+(one, two); //three = one + two } Is a friend function necessary in this case? No because LH operand is an instance of the class.
Operator Functions as Class Members vs. as friend Functions Non-member overloaded operator functions • Enable the operator to be commutative HugeInteger bigInteger; int integer; bigInteger = integer + bigInteger; or bigInteger = biginteger + integer;
Global Operator Overloading • Similar to friend Function Overloading, Except the Keyword friend is Omitted and Global Functions CANNOT ACCESS private Members class complex{ //All Public Members! public: int re, im; complex(int ip1 = 0, int ip2 = 0) :re(ip1), im(ip2){} }; void operator!(complex a) { int temp = a.re; a.re = a.im; a.im = temp; cout << "Real: " << a.re << endl; cout << "Imaginary: " << a.im << endl; } main() { complex one(1,2); operator!(one); !one; }
Overloading of Operators Having a Variable Arity • Operators Such as + and - Can be Unary or Binary • Overloading of Such Operators Involves Creating a Unary Function (One Operand) and a Binary Function (Two Operands) • Only if Both the Forms are Used, They Need to be Implemented class number{ int n; public: number(int x = 0):n(x){} number operator-(){n = -n; return *this;} number operator-(number ip) {n = n – ip.n; return *this;} }; main(){ number one(1), two(2), three; one = -one; //unary operator three = one - two; //three.n = -3 }
Operators with Prefix and Postfix Forms • Separate Functions for Each -- Prefix and Postfix -- Forms are Needed • Prefix Form is Treated as an Unary Operator • Postfix Form is Treated as a Binary Operator
Prefix Overloaded Function -- Example class number{ int n; public: number(int x):n(x){}; //Constructor //prefix operator -- unary number operator++(); }; number number::operator++(){ n++; return *this;} main(){ number one(10); //one.n = 10 one++; //one.n = 11 }
Postfix Overloaded Function -- Example • Postfix Operator is Implemented as a Binary Operator with an int Argument with a Default Value of 0 . When specifying an overloaded operator for the postfix form of the increment or decrement operator, the additional argument must be of type int; specifying any other type generates an error. class number{ int n; public: number(int x):n(x){}; //Constructor //postfix operator -- binary -- int argument number operator++(int); }; number number::operator++(int y) {if (y != 0) n += y; else n++; return *this;} main() { number one(10); // one.n = 10 one++; // one.n = 11 one.operator++(2); // one.n = 13 } • There is no syntax for using the increment or decrement operators to pass these values other than explicit invocation, as shown in the preceding code. A more straightforward way to implement this functionality is to overload the addition/assignment operator (+=).
Special Overloading Forms • A Few Operators Require Special Treatments During Overloading • Conversion Operator • const Array Operator • Function Call -- Parenthesis Operator • Stream Insertion -- << Operator • Stream Extraction -- >> Operator • Pointer to Member -- -> Operator • Assignment Operator • new Operator • delete Operator
Overloading Stream-Insertion and Stream-Extraction Operators • Overloaded << and >> operators • Must have left operand of types ostream&, istream& respectively • It must be a non-member function (left operand not an object of the class) • It must be a friendfunction if it accesses private data members
1 // Fig. 18.3: fig18_03.cpp 2 // Overloading the stream-insertion and 3 // stream-extraction operators. 4 #include <iostream> 5 6 using std::cout; 7 using std::cin; 8 using std::endl; 9 using std::ostream; 10 using std::istream; 11 12 #include <iomanip> 13 14 using std::setw; 15 16 class PhoneNumber { 17 friend ostream &operator<<( ostream&, const PhoneNumber & ); 18 friend istream &operator>>( istream&, PhoneNumber & ); 19 20 private: 21 char areaCode[ 4 ]; // 3-digit area code and null 22 char exchange[ 4 ]; // 3-digit exchange and null 23 char line[ 5 ]; // 4-digit line and null 24 }; 25 26 // Overloaded stream-insertion operator (cannot be 27 // a member function if we would like to invoke it with 28 // cout << somePhoneNumber;). 29 ostream &operator<<( ostream &output, const PhoneNumber &num ) 30 {
31 output << "(" << num.areaCode << ") " 32 << num.exchange << "-" << num.line; 33 return output; // enables cout << a << b << c; 34 } 35 36 istream &operator>>( istream &input, PhoneNumber &num ) 37 { 38 input.ignore(); // skip ( 39 input >> setw( 4 ) >> num.areaCode; // input area code 40 input.ignore( 2 ); // skip ) and space 41 input >> setw( 4 ) >> num.exchange; // input exchange 42 input.ignore(); // skip dash (-) 43 input >> setw( 5 ) >> num.line; // input line 44 return input; // enables cin >> a >> b >> c; 45 } 46 47 int main() 48 { 49 PhoneNumber phone; // create object phone 50 51 cout << "Enter phone number in the form (123) 456-7890:\n"; 52 53 // cin >> phone invokes operator>> function by 54 // issuing the call operator>>( cin, phone ). 55 cin >> phone; 56 57 // cout << phone invokes operator<< function by 58 // issuing the call operator<<( cout, phone ). 59 cout << "The phone number entered was: " << phone << endl; 60 return 0; 61 }
Enter phone number in the form (123) 456-7890: (800) 555-1212 The phone number entered was: (800) 555-1212
Converting between Types • Cast operator • Convert objects into built-in types or other objects • Conversion operator must be a non-static member function. • Cannot be a friend function • Do not specify return type For user-defined class A A::operator char *() const; // A to char A::operator int() const; //A to int A::operator otherClass() const; //A to otherClass • When compiler sees (char *) s it calls s.operator char*()
Converting between Types (cont) • The compiler can call these functions to create temporary objects. • If s is not of type char * Calls A::operator char *() const; for cout << s;
Special overloading forms - Example • Special Forms Example
Acknowledgements • These slides were originally development by Dr. Uday Murthy and Dr. Rajeev Raje. • Some contents comes from the Deitel slides that accompany your text. • Some information regarding the postfix form the increment and decrement operators comes from MSDN.