Download presentation
Presentation is loading. Please wait.
1
Lecture 9: Operator Overloading
Object Oriented Programming (C++) Lecture 9: Operator Overloading
2
Contents The requirement of operator overloading Operator function
How to overload operator Members and friends Increment & Decrement Conversion operator
3
The requirement of operator overloading
int a, b; a+b; //ok a-b; //ok a*b; //ok a/b; //ok class complex ; complex a, b; a+b; //error a-b; //error a*b; //error a/b; //error ?
4
type operator @ (<arg_list>)
The predefined operators in C++ can’t provide operations for user-defined data types. So we need operator overloading. Declaration: type (<arg_list>) where type means the type of the returning means the operation symbol, such as “+”, “ -”, “&”, and so on.
5
Example: class Complex { double re, im; public:
Complex (double r=0, double i=0) { re=r; im=i;} Complex operator+ (Complex &) ; Complex operator* (Complex &) ; Complex operator+(double) ; void show(); };
6
Complex Complex ::operator+ (Complex &c)
{ Complex temp; temp.re=re+c.re; temp.im=im+c.im; return temp; } Complex Complex ::operator+ (double a) temp.re=re+a; temp.im=im;
7
Complex Complex ::operator* (Complex &c)
{ Complex temp; temp.re=re*c.re-im*c.im; temp.im=re*c.im+im*c.re; return temp; } void Complex ::show() cout<<"Re:"<<re<<'\t'<<"Im:"<<im<<endl;
8
c3=c1+c2;// operator+ (complex &c) c3=c1*c2; // operator* (complex &c)
void main() { Complex c1(3,4),c2(5,6),c3; c1.show(); c2.show(); c3.show(); c3=c1+c2;// operator+ (complex &c) c3=c1*c2; // operator* (complex &c) c3=c3+3.0; // operator+ (double) } Result: Re: Im: 4 Re: Im: 6 Re: Im: 0 Re: Im: 10 Re: Im: 38 Re: Im: 38
9
The programmer defines complex: :operator+() and complex: :operator
The programmer defines complex: :operator+() and complex: :operator*() to provide meanings for + and *, respectively. For example, if a and b are of type complex, a+b means a.operator+(b).
10
Contents The requirement of operator overloading Operator function
How to overload operator Members and friends Increament & Decreament Conversion operator
11
Operator function Functions defining meanings for the following operators can be declared: * / % ^ & | ~ ! = < > = -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || >* , -> [] () new new[] delete delete[]
12
The following operators cannot be defined by a user:
:: (scope resolution; §4.9.4, §10.2.4), . (member selection; §5.7), and .* (member selection through pointer to member; §15.5). Other operators such as ?:,sizeof, typeid,etc. also cannot be overloaded.
13
Operator overloading rules:
It is not possible to define new operator tokens, but you can use the function call notation when this set of operators is not adequate. For example, use pow(), not **. The number of operands can’t be changed. The priority for operators can’t be changed. The syntax for operators can’t be changed. The combination sequence can’t be changed. Obey to the function overloading rules.
14
Contents The requirement of operator overloading Operator function
How to overload operator Members and friends Conversion operator Overloading for other operators
15
How to overload operator
Operator overloaded as member functions. 1. For any binary can be interpreted as 2. For any can be interpreted as In this class, I will discuss how to overload operators. There are two ways to overload an operator. The first one is that it can be overloaded as member functions of a class. The second is that it can be also overloaded as non-member functions. Let’s see the first one. For any binary operator, there are two operands that are aa and bb, respectively. So, can be interpreted as In other words, we call the first operand aa’member function, with the second operand as an argument, to implement
16
Operator overloaded as nonmember functions.
1. For any binary can be interpreted as bb); 2. For any can be interpreted as Now let’s discuss the second case. In this case, we overload operators as nonmember functions.
17
Example1 class X { // members (with implicit ‘this’ pointer):
X* operator&() ; // prefix unary & (address of) X operator&(X) ; // binary & (and) X operator++(int) ; // postfix increment X operator++() ; // prefix increment X operator&(X,X) ; // error: ternary X operator/() ; // error: unary “ /” }; Now let’s an example of operators as member functions. There are two correct operators that have the same name & but with different meanings. Let’s see the first & operator. Because there is no argument for the member function, the & operator just has only one operand that is this object. It means to take the address of this object. The second one has one argument type X, so it is a binary operator. Therefore, the compiler will interpret it as a logic and, or bit and binary operator. There are two ++ operators, that is, postfix and prefix increments. Obviously, the postfix ++ operator is implemented as a function with two arguments. But in fact, both the postfix and prefix increments has only one operand, and they are unary operators. Implementing the postfix ++ operator as a function with two arguments is to discriminates the two operators since they have the same name but with different orders. Because C++ language can not distinguish the postfix and prefix increment functions. Let’s see the last two lines of code. The & operator has two arguments, so it will be a ternary operator. Therefore, it’s wrong. Let see the division operator, there is no argument for member function operator /, so the division operator will be interpreted as a unary operator.
18
Example2 // nonmember functions :
X operator-(X) ; // prefix unary minus X operator-(X,X) ; // binary minus X operator--(X&,int) ; // postfix decrement X operator--(X&) ; // prefix decrement X operator-(); // error: no operand X operator-(X,X,X) ; // error: ternary X operator%(X) ; // error: unary % Now let’s come to the nonmember functions for operators. The number of arguments is the same of operands involved for the operator. I think operators overloaded as nonmember functions are intuitively understood than member functions. For example, for a unary operator -, the negative operator is implemented as a common function with one argument. For a binary operator minus with two operands, there are two arguments for the common functions. For a postfix decrement --, the second argument is not used but for discrimination postfix from prefix. The prefix operator –- has only one operand that is the same as the number of the implement function. For this code line, there is no argument, so there is no operand for the operator, and it is weird and the compiler system would raise an error. For the minus operator with three operands, the compiler also gives an error. The modulo operator has only one argument, but it should has two operands, so the compiler encounters an error.
19
Question 1: class complex { public: complex(double r=0,double i=0);
Please point out the errors and correct them class complex { public: complex(double r=0,double i=0); complex operator + (complex&, complex&);//add complex operator *(complex&); //multiply friend complex operator -(complex&); //negative void print() const; private: double real, imag; };
20
Question 2: class X { X* operator &() ; // (address of)
Please point out which is right or wrong class X { X* operator &() ; // (address of) X operator &(X) ; // (and) X operator &(X,X) ; // (and) X operator /() ; //(divide) //…… }; Who would like to point out which is right or wrong? If an operator is wrong, please explain the reason.
21
Question 3: X operator-(); // negative X operator-(X,X) ; // minus
Please point out which is right or wrong // nonmember functions : X operator-(); // negative X operator-(X,X) ; // minus X operator-(X) ; // negative X operator-(X,X,X) ; // minus X operator%(X) ; // modulo Who would like to point out which is right or wrong? If an operator is wrong, please explain the reason.
22
Give the output of the following program 1
#include <iostream.h> class complex { public: complex(double r=0,double i=0); complex operator +(const complex& c); complex operator -(const complex& c); complex operator -(); void print() const;// const member function private: double real,imag; }; complex::complex(double r,double i) :real(r),imag(i){} +operation -operation Negative operation Let see a relatively complete example, that is the implementation of class complex. For the class complex, it has two private member variables, real and imag, which stands for the real part and imaginary part of an complex. We implemented a constuctor for the class with two default aruments and a display function print. We also overloaded three operators as member function, which are addition operator, subtraction operator, and negative operator. This slides show the declaration of class complex.
23
complex complex::operator +(const complex& c) { double r=real+c.real;
double i=imag+c.imag; return complex(r,i); } complex complex::operator -(const complex& c) double r=real-c.real; double i=imag-c.imag; Let see the plus operator. The function is to add a complex object c and this object to create a new complex object with a real part r and an imaginary part i, and return the new complex object. The subtraction operator is to subtract a complex object c from this object, and also create a new complex object with a real part r and an imaginary part i, and return the new complex object.
24
complex complex::operator -() { return complex(-real,-imag); }
void complex::print() const cout<<"("<<real<<","<<imag<<")"<<endl; void main() complex c1(2.5,3.7),c2(4.2,6.5); complex c; c=c1-c2; c.print(); c=c1+c2; The negative operator is to return a new complex object with real and imaginary parts that are just negative values of this object. The print member function is to display the real and imaginary part of this object. Now let’s see how to use the operators. In the main function, we defined three objects of class complex, which are named as c1,c2, and c. The constructors initialize the three complexes. Among them, c1 is a complex with real and imaginary parts (2.5 and 3.7), c2 is a complex with real and imaginary parts (4.2,6.5), and c is a zero complex. We can use mathematical expressions for two complex subtractions like this, c=c1-c2. Then we display the result using print member function of object c. C=c1+c2 means the addition of the two complexes c1 and c2, and store the result in c. c=c1.operator-(c2); c=c1.operator-(c2);
25
complex c1(2.5,3.7),c2(4.2,6.5); c.print(); c=-c1; } The output is:
c=c1.operator-(); The output is: (-1.7,-2.8) (6.7,10.2) (-2.5,-3.7) Then we display the result of object c. C=-c1 means that c stores the negative values of a complex c1. According to the output, we can check the result, it’s correct. We can find that using operators for a user-defines type can simplify programming and improve readabilities of a program.
26
Give the output of the following program 2
#include <iostream.h> class complex { public: complex(double r=0,double i=0); friend complex operator + (const complex& c1,const complex& c2); friend complex operator - friend complex operator -(const complex& c); void print() const; private: double real,imag; }; +operation -operation We implement the three operators as nonmember functions. To make the operator functions to access the private member variables, we define the three common operator functions as a friend of class complex. Negtive operation
27
complex::complex(double r,double i) { real=r; imag=i; }
complex operator +(const complex& c1, const complex& c2) double r=c1.real+c2.real; double i=c1.imag+c2.imag; return complex(r,i); complex operator -(const complex& c1, The first function is a constructor for the class complex to initialize an object. The second one is an addition operator. The function add two complexes c1 and c2 together, and return the result. The third one is a subtraction operator, which subtract a complex c1 from complex c2, and return the result.
28
double r=c1.real-c2.real; double i=c1.imag-c2.imag;
return complex(r,i); } complex operator -(const complex& c) { return complex(-c.real,-c.imag); void complex::print() const cout<<"("<<real<<","<<imag<<")"<<endl; void main() complex c1(2.5,3.7),c2(4.2,6.5); The negative operator function just returns a complex with negative values of a complex c. The print function is not changed, used for display the value of a complex.
29
complex c1(2.5,3.7),c2(4.2,6.5); complex c; c=c1-c2; c.print();
} c=operator -(c1,c2); c=operator +(c1,c2); c=operator -(c1); The output is: (-1.7,-2.8) (6.7,10.2) (-2.5,-3.7) The result is correct and the same as the version of member functions. I think the nonmember function version is more intuitively consistent to our human mind than member function complex c1(2.5,3.7),c2(4.2,6.5);
30
Contents The requirement of operator overloading Operator function
How to overload operator Members and friends Increament & Decreament Conversion operator
31
Comparison between Members and friends
Actually, unary operators should be overloaded as member functions of a class while binary operators as nonmember functions or friends. We had better overload some binary operations(such as:=, [], ())as member function. To more clearly understand, we should overload unary operators as member functions of a class while we overload binary operators as nonmember functions or friends. We’d better overload some binary operations, such as assignment, square brackets, round brackets, as member function
32
Contents The requirement of operator overloading Operator function
How to overload operator Members and friends Increament & Decreament Conversion operator
33
Increment and Decrement
Tell the results: #include <iostream.h> void main() { int x; x=5; int y=x++; cout<<y<<'\t'<<x<<endl; } #include <iostream.h> void main() { int x; x=5; int y=++x; cout<<y<<'\t'<<x<<endl; }
34
Increment and Decrement
The increment and decrement operators are unique among C++ operators in that they can be used as both prefix and postfix operators. Consequently, we must define prefix and postfix increment and decrement in class.Traditional program: void f1(T a) // traditional use { T v[200]; T* p= &v[0] ; p--; *p = a; // Oops: ‘p’ out of range, uncaught ++p ; *p = a ; // ok }
35
Increment and Decrement
Declaration form: type operator ++(); //prefix type operator ++(int) //postfix type operator --(); //prefix type operator --(int) //postfix Note: The int argument is used to indicate that the function is to be invoked for postfix application of ++. This int is never used; the argument is simply a dummy used to distinguish between prefix and postfix application.
36
Example 1: #include <iostream.h> class demo { int x; public:
demo(int i=0) {x=i;} int operator ++() {return ++x;} int operator ++(int) {return x++;} int GetX() {return x;} }; Let’s a simple example of prefix and postfix increments. In the prefix ++ operator, we just use prefix ++ operator of basic type; Similarly, postfix ++ operator of basic type is also used. As we can see, the argument of postfix function is not used.
37
int i=d++; //d.operator++(0)
void main() { demo d(5); //d.x=5 int i=d++; //d.operator++(0) cout<<"i="<<i<<'\t'<<"d.x="<<d.GetX()<<endl; i=++d; // d.operator++() } We define an object of class demo with an argument 5 to assign to the private variable of the object. Then we call the postfix operator by writing int i=d++; At this moment, i is equal to 5, d.x equals 6. Then we call the prefix operator by writing int i=++d; At this moment, i is equal to 7, d.x equals 7. The bottom of this slide shows the output result of this program. Result: i=5 d.x=6 i=7 d.x=7
38
Example 2: class Ptr{ T* p; T * array ; int size ; public:
Ptr(T * p , T * v , int s ); Ptr(T * p ); Ptr & operator ++(); // prefix Ptr operator ++(int); // postfix Ptr &operator --(); / / prefix Ptr operator --(int); // postfix T& operator*() ; };
39
Increment and decrement as friend function
Declaration form: type operator ++(class_name &); //prefix type operator ++(class_name &, int) //postfix type operator --(class_name &); //prefix type operator --(class_name &, int) //postfix class_name is the name of the class.
40
Example 1: #include <iostream.h> class demo { int x; public:
demo(int i=0) {x=i;} friend int operator ++(demo&); friend int operator ++(demo&, int); int GetX() {return x;} };
41
int operator ++(demo&d)
{ return ++d.x; } int operator ++(demo&d, int) return d.x++;
42
void main() { demo d(5); int i=d++;
cout<<"i="<<i<<'\t'<<"d.x="<<d.GetX()<<endl; i=++d; } Result: i=5 d.x=6 i=7 d.x=7
43
Example 2: #include<iostream.h> class RMB{ public:
RMB(unsigned int d, unsigned int c); RMB operator +(RMB&); friend RMB& operator ++(RMB&); void display(){ cout <<(yuan + jf / 100.0) << endl; } protected: unsigned int yuan; unsigned int jf; };
44
RMB::RMB(unsigned int d, unsigned int c)
{ yuan = d; jf = c; while ( jf >=100 ){ //make sure jf<100 yuan ++; jf -= 100; }} RMB RMB::operator+(RMB& s1) { unsigned int jf1 = jf + s1.jf; unsigned int yuan1 = yuan + s1.yuan; RMB result( yuan1, jf1 ); return result; // return RMB( yuan1, jf1 ); }
45
The output: 4.11 RMB operator ++(RMB& s) { s.jf ++;
if(s.jf >= 100){ s.jf -= 100; s.yuan++; } return s;} void main(){ RMB d1(1, 60); RMB d2(2, 50); RMB d3(0, 0); d3 = d1 + d2; ++d3; d3.display();} The output: 4.11
46
Contents The requirement of operator overloading Operator function
How to overload operator Members and friends Increament & Decreament Conversion operator
47
Conversion operator Tell the results: #include <iostream.h>
void main() { int x=5; int y=4; cout<<x/y<<endl; } #include <iostream.h> void main() { int x=5; int y=4; cout<<(float)x/y<<endl; } 1 1.25
48
Conversion operator Declaration form: class_name::operator type( );
This overloading operator has no argument and returns the value of the type. It is called type conversion operator, which is used to convert an object of a class to the corresponding type. This function can be used only as member function and cannot be used as non-member function.
49
Example 1: class Complex { double re, im; public:
Complex (double r=0, double i=0) { re=r; im=i;} operator double( ) {return re;} Complex operator+ (Complex &) ; Complex operator+(double) ; void show(); };
50
cout<<double(c); }
void main() { Complex c(3,4); cout<<double(c); } Result: 3
51
Example 2: class person{ char *Name; int Age; char Sex; public:
person(person&); ~person(); operator char *( ){return Name;} operator int( ){return Age;} operator char( ){return Sex;} void show(); };
52
Person p(“Wangping”, 23, f);
void main() { Person p(“Wangping”, 23, f); cout<<(char*)p<<‘t’<<int(p)<<‘\t’<<char(p)<<endl } Result: Wangping 23 f
53
Subscripting Declaration form: type operator [](arg);
Arg is the argument of the function and it can be just only one. This arg gives the value of the subscripting. It can only be regarded as non-static member function.
54
Example : class Demo{ int Vector[5]; public: Demo( ) { }
int &operator [ ](int i) { return Vector[i]; } };
55
for(int i=0; i<5; i++) v[i]=i+1; for(i=0; i<5; i++)
void main() { Demo v; for(int i=0; i<5; i++) v[i]=i+1; for(i=0; i<5; i++) cout<<v[i]<<endl; } 1 2 3 4 5
56
The End! Any Question?
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.