Download presentation
Presentation is loading. Please wait.
Published byMelanie Kennedy Modified over 9 years ago
1
Operator Overloading 1
2
Introduction Let’s define a class for Complex numbers: class Complex { private: double real, image; public: Complex () : real(0.0), image(0.0) {} Complex (double r) : real(r), image(0.0) {} Complex (double r,double i):real(r),image(i) {} double getReal() const {return real;} double getImage() const {return image;} void setReal(double r) {real = r;} void setImage(double i) {image = i;} }; 2 How can we make this code even simpler?
3
Example – cont. Which of the following is a valid code? 3 int x,y; x = 5; y = 6; x += y; double x,y; x = 5; y = 6; x += y; Complex x(1,1),y(1,2) ; x += y; //compiler error We need to overload standard operators to work on user-defined types. What to do? no match for operator+= for Complex
4
Adding ‘Complex’s – First Try Let’s add an function addComplex( const Complex& x) to our class Complex: class Complex{ … public: … void addComplex(const Complex& x) { real += x.real; image += x.image; } }; 4
5
Adding ‘Complex’s – First Try Cont 5 o The code works, but isn’t very elegant: Complex x(1,1),y(1,2); x.addComplex(y); o On the other hand, the following doesn’t work, but it’s indeed elegant: Complex x(1,1), y(1,2); x += y; o Is there anything else we can do to make the elegant code work as well?
6
Operator Overloading Operator overloading provides a more natural way to define and use operators ( +,-, etc.) for user defined types (classes and enumerations). Need to take care not to overdo it - this is a very easy way to write incomprehensible code If the users of your code need to read documentation to use your operators, you are probably doing it wrong! 6
7
Operator Overloading We overload operator OP by defining a function named operatorOP, where OP is one of the predefined C++ operators. Overloadable operators ( OP ): There exist also Non-overloadable operators. 7 &^%/*-+ ><=,!~| ==>><<--++>=<= %=/=-=+=||&&!= ()[]>>=<<=*=|=^= delete[]deletenew[]new->*->&=
8
Operator Overloading example Let’s define “+=” operator for Complex class: class Complex{ … public: void operator += (const Complex& x) { real += x.real; image += x.image; } }; Are we done here? What about: Complex n1(1,2), n2(3,4), n3; n3 += n2 += n1 ; 8
9
Operator Overloading example class Complex{ … public: Complex& operator += (const Complex& x) { real += x.real; image += x.image; return *this; } }; //usage Complex n1(1,2), n2(3,4); n1 += n2; double d = 0.0 ; n1 += d ; // OK: x.operator+=(Complex(y)) is // invoked. d += n1 ; //Error – ??? 9
10
Adding Complex Numbers //We want to be able to write: Complex x(1,1), y(2,2), z; z = x + y; //OR z.operator=(x.operator+(y)); // Thus class Complex { private: double real, image; public:... Complex operator+ (const Complex& x) const; Complex& operator= (const Complex& x); }; 10
11
Adding Complex Numbers – Cont. //Implementation: inline Complex Complex::operator+ (const Complex& num) const { return Complex(real + num.real, image + num.image); } inline Complex& Complex::operator= (const Complex& num) { real = num.real; image = num.image; return *this; } Note that the operators receive their left operand as “ this ”: z = x + y; // is translated to z.operator=(x.operator+(y)); 11
12
Operators as Non-members Operators can also be implemented as non-member functions. Overloaded “ operator- ” of A, as non- member : A operator-(const A&, const A&); Example: class Complex{ public: … //Operator “+” as member function Complex operator+(const Complex& num) const ; }; // Operator “-” as non-member function inline Complex operator-(const Complex& num1, const Complex& num2 ) { … } ; 12
13
Non Complex Right Operand How can we define operator- for: Complex – int ? Implement operator- that accepts two Complex. Requires a way of casting int to Complex (which we already have - constructor with a single parameter double ). Example: Complex x; int y; x - y; // operator-(Complex, Complex(y)) // or Complex.operator-(Complex(y)) Add overloaded operator- that accepts a single int as member function of the Complex class or operator-(const Complex&, int) as non-member function. Example: Complex x; int y; x - y; // Complex.operator-(int) // or operator-(Complex,int) 13
14
Non Complex Right Operand [1] Using implicit conversion: class Complex { … public: … Complex (double r) : real(r), image(0.0) {} Complex operator - (const Complex& rNum) const { return Complex(real-rNum.real,image-Rnum.image); } }; 14
15
Non Complex Right Operand [2] Special overload for int, member function: class Complex { … public: Complex operator - (const Complex& rNum) const; Complex operator - ( int real ) const { return *this - Complex(real) ; } }; 15
16
Non Complex Right Operand [3] Special overload for int, non-member function: class Complex { … public: Complex operator - (const Complex& rNum) const; }; inline Complex operator-( const Complex& rNum, int real) { return rNum - Complex(real) ; } 16
17
Non Complex Left Operand How can we define operator- for int – Complex ? Implement operator that can accept (int,Complex) as non-member function, by using operator-(const Complex&, const Complex&). Example: // implementation as non-member function inline Complex operator- (const int real, const Complex& rNum){ return Complex(real,0) - rNum ; } // usage Complex x ; int y ; y-x; // operator-(int,Complex) Can we implement it as a member function? 17
18
Operator Overloading: Parameters Some operators are both unary and binary (e.g. “-” ). Implemented as two functions that differ in the number of their parameters. The precedence and associativity of an operator cannot be changed. Example: Complex x(1,1), y(2,3), z ; y + z + w // y.operator+( z.operator+(w) ) x == y + z // x.operator == ( y.operator+(z) ) The number of operands, for a given operator, cannot be changed. 18
19
To Overload or Not to Overload? Overloaded operators make no guarantees about the order in which operands are evaluated. Logical AND ( && ), logical OR ( || ), and comma (, ) operators are usually not overloaded, since all their operands, no matter what, will be always evaluated, and this in some arbitrary order! This is opposite to intuition: the built-in versions of these operators always evaluate operands left-to-right, and logical AND/OR may not evaluate some operands at all! 19
20
To Overload or Not to Overload? If not explicitly defined, an address_of ( & ) operator for your class is synthesized by the compiler. In case we explicitly overload that operator, we lose its default implementation (override). It is strongly recommended to avoid overloading the operator &. The same axiom holds for the “new”, “delete” and “delete[]” operators. 20
21
To Overload or Not to Overload? Do not overload operators that have no meaning for your class. For example, if you define Matrix class, you will probably overload “+” and “-” operators, but it seems strange to overload “ ” operators, since their meaning is not commonsensical. 21
22
Class Member vs. friend (1) Class member implementation (reminder): class Complex { private: … public: Complex operator+ (const Complex&) const; }; inline Complex Complex::operator+(const Complex& z) const { return Complex (real + z.real, image + z.image); } // usage: Complex x(1,1), y(2,2), z; z = x + y; 22
23
Class Member vs. friend (2) “friend” implementation: class Complex { private: … friend Complex operator+ (const Complex& z1, const Complex& z2); public: … }; inline Complex operator+ (const Complex& z1, const Complex& z2) { return Complex (z1.real+z2.real,z1.image+z2.image); } // usage: Complex x(1,1), y(2,2), z; z = x + y; //OR z.operator=(operator+(x,y)); Why do we put friend in private ? 23
24
Class Member vs. Nonmember (1) The assignment “=“, subscript “[]”, call-function “()”, and member access arrow “->” operators MUST be defined as class members. Otherwise, it is a compilation error. The compound-assignment ( +=, -=, etc.), and other operators which changes object’s state, are typically implemented as class members. Good practice is to define read-only operators as independent (non-member) functions. For example: +, -, ==, >, =,=<. 24
25
Class Member vs. Nonmember (2) Example: Complex x, z; [1] x+=z; x+=y; // OK, change their left // operand, Complex object. [2] y-z; y+x; // OK, (+,- should be implemented // as a non-member function) operator+= implementation, for example [1]: inline Complex& operator+= (const Complex& op2) { return (*this = (*this) + op2); } 25
26
Class Member vs. Nonmember (3) Input ( >> ) and Output ( << ) operators MUST be implemented as non-member functions. Why? Because the other option is to make them members of the istream/ostream classes And we cannot change these classes! 26
27
Class Member vs. Nonmember (4) class Complex { private: friend ostream& operator<<(ostream &os, const Complex & cNum ); friend istream& operator>>(istream &is, Complex & cNum ); … }; inline ostream& operator<<(ostream &os, const Complex& cNum) { return os << "(" << cNum.real << "," << cNum.image << ")"; } inline istream& operator>>(istream &is, Complex& cNum ) { is >> cNum.real >> cNum.image ; // validity check should be here return is ; } Can we implement these two as non-friends ? 27
28
Class Member vs. Nonmember (5) // implementation as non-friends: inline ostream& operator<<( ostream &os, const Complex & cNum) { os << "( " << cNum.getReal() <<", " << cNum.getImage() << " )" ; return os ; } inline istream& operator>>( istream &is, Complex & cNum ){ double tReal, tImage ; is >> tReal >> tImage ; // validity check should be here cNum.setReal( tReal ) ; cNum.setImage( tImage ) ; return is ; } 28
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.