2012年2月16日 星期四

Operator Overloading


Operators in C++ may be overloaded in the same way that functions are overloaded. In C, the + (plus) operator is "overloaded" to work for int or float values.  In C++, this concept is extended to include class types.

Notes:

•You may overload the following operators:
+    -    *    /    %    ^    &    |
~    !    ,    =    <    >    <=   >=
++   --   <<   >>   ==   !=   &&   ||
+=   -+   /=   %=   ^=   &=   |=   *=
<<=  >>=  []   ()   ->   ->*  new  delete

•Most operators may be overloaded, both binary and unary operators. The following operators may not be overloaded:
.         direct member
.*        direct pointer to member
::        scope resolution
? :       ternary

•To overload an operator, create a function called operator@ where @ is the operator symbol you wish to overload.

•Operator precedence is still in effect for overloaded operators and may not be changed.

•Default arguments are not allowed in overloaded operator functions.

•For an expression involving binary operators, A + B means:
A.operator+(B)    if operator+() is a class member function
operator+(A,B)    if operator+() is a non-class member function

•An overloaded operator function may be defined as a class member function, a friend function, or even a non-friend function.

•You may not overload an operator (redefine) for the built-in primitive types.  In other words, if a and b are ints, then a+b will always be (int) a+b.

•You may not create any new operator symbols

Example 6-3 - Fraction class with overloaded +  and ! operators

1      // File: ex6-3.cpp overloaded + and ! operator for fraction class
2     
3      #include <iostream>
4      using namespace std;
5     
6      class fraction
7      {
8        private:
9            int numer;
10            int denom;
11        public:
12            fraction(int n = 0, int d = 1);
13            void operator!(void) const;
14            fraction operator+(const fraction&);
15      };
16     
17      fraction::fraction(int n, int d)
18      {
19        numer = n;
20        denom = d;
21      }
22     
23      void fraction::operator!(void) const
24      {
25        cout << numer << '/' << denom << endl;
26        return;
27      }
28     
29      fraction fraction::operator+(const fraction& f2)
30      {
31        fraction temp(0,0);
32        temp.numer = numer * f2.denom + f2.numer * denom;
33        temp.denom = denom * f2.denom;
34        return temp;
35      }
36     
37      int main(void)
38      {
39        fraction f(3,4);         
40        fraction g(2,3);
41        fraction h = f + g;         // Do you need a default ctor here?
42        !h;                                           // prints 17/12
43     
44        return 0;
45      }


In this example operator+ returns a fraction by value.  Is it possible or appropriate to have the function return by reference or have a void return?

Line 41:  What is the difference between fraction h = f + g;  and fraction h(f+g);

In this example, operator+ is defined as a friend function.

Example 6-4 - A friendly overloaded +

1      #include <iostream>
2      using namespace std;
3     
4      class fraction {
5        private:
6           int numer, denom;
7        public:
8          fraction(int n = 0, int d = 1);
9          void operator!(void) const;
10        friend  fraction operator+(const fraction&,const fraction&);
11      };
12     
13     
14      fraction::fraction(int n, int d) {
15        numer = n;
16        denom = d;
17      }
18     
19      void fraction::operator!(void) const {
20        cout << numer << '/' << denom << endl;
21      }
22     
23      // fraction friend function
24      fraction operator+(const fraction& f1,const fraction& f2) {
25        fraction temp(f1.numer *f2.denom + f2.numer * f1.denom,
26           f1.denom * f2.denom);
27        return temp;
28      }
29     
30     
31      int main(void) {
32        fraction f(3,4);
33        fraction g(2,3);
34        fraction h = f + g;
35        !f;
36        !g;
37        !h;
38        return 0;
39      }


******  Output  ******

3/4
2/3
17/12

What's the better approach, example 6-3 or example 6-4?

This example demonstrates a more "complete" set of overloaded operators for the fraction class. Notice that all operators are specified as member functions

Example 6-5 - The Overloaded fraction class

1      // File: ex6-5.cpp
2      #include <iostream>
3      #include <cassert>
4      using namespace std;
5     
6      class fraction {
7            int numer, denom;
8        public:
9            fraction(int = 0, int = 1);
10            void operator!(void) const;       // print the fraction
11            fraction& operator~(void);        // reduce the fraction
12            fraction operator-(void) const;   // negative of fraction
13            fraction operator*(void) const;   // reciprocal of fraction
14            fraction& operator+=(const fraction&);
15            fraction& operator-=(const fraction&);
16            fraction& operator*=(const fraction&);
17            fraction& operator/=(const fraction&);
18            fraction operator+(int) const;
19            fraction operator-(int) const;
20            fraction operator*(int) const;
21            fraction operator/(int) const;
22            bool operator>(const fraction&) const;
23            bool operator<(const fraction&) const;
24            bool operator>=(const fraction&) const;
25            bool operator<=(const fraction&) const;
26            bool operator==(const fraction&) const;
27            bool operator!=(const fraction&) const;
28            fraction operator+(const fraction&) const;
29            fraction operator-(const fraction&) const;
30            fraction operator*(const fraction&) const;
31            fraction operator/(const fraction&) const;
32              fraction& operator++();      // prefix op returns by ref
33              fraction operator++(int);      // postix op returns by value
34      };
35     
36      // member function definitions
37      fraction::fraction(int n, int d) {
38        assert(d != 0);
39        numer = n;
40        denom = d;
41      }
42     
43      // print the fraction
44      void fraction::operator!(void) const {
45        cout << numer << '/' << denom << endl;
46      }
47     
48      // reduce the fraction
49      fraction& fraction::operator~(void) {
50      int min;
51      // find the minimum of the denom and numer
52        min = denom < numer ? denom : numer;
53        for (int i = 2; i <= min; i++) {
54            while ((numer % i == 0) && (denom % i == 0)) {
55                numer /= i;
56                denom /= i;
57            }
58        }
59        return *this;
60      }
61     
62      // negate the fraction
63      fraction fraction::operator-(void) const {
64        return fraction(-numer,denom);
65      }
66     
67      // fraction reciprocal
68      fraction fraction::operator*(void) const {
69        return fraction(denom,numer);
70      }
71     
72      fraction& fraction::operator+=(const fraction& f) {
73        numer = numer*f.denom+denom*f.numer;
74        denom = denom*f.denom;
75        return *this;
76      }
77     
78      fraction& fraction::operator-=(const fraction& f) {
79        *this += (-f);
80        return *this;
81      }
82     
83      fraction& fraction::operator*=(const fraction& f) {
84        numer = numer*f.numer;
85        denom = denom*f.denom;
86        return *this;
87      }
88     
89      fraction& fraction::operator/=(const fraction& f) {
90        *this *= (*f);
91        return *this;
92      }
93     
94      bool fraction::operator>(const fraction& f) const {
95        return (float) numer/denom > (float) f.numer/f.denom;
96      }
97     
98      bool fraction::operator<(const fraction& f) const {
99        return f>*this;
100      }
101     
102      bool fraction::operator==(const fraction& f) const {
103        return numer*f.denom == denom*f.numer;
104      }
105     
106      bool fraction::operator!=(const fraction& f) const {
107        return !(*this == f);
108      }
109     
110      bool fraction::operator<=(const fraction& f) const {
111        return !(*this > f);
112      }
113     
114      bool fraction::operator>=(const fraction& f) const {
115        return !(*this<f);
116      }
117     
118      fraction fraction::operator+(const fraction& f) const {
119        return fraction(numer*f.denom+denom*f.numer,denom*f.denom);
120      }
121     
122      fraction fraction::operator-(const fraction& f) const {
123        return fraction(numer*f.denom-denom*f.numer,denom*f.denom);
124      }
125     
126      fraction fraction::operator*(const fraction& f) const {
127        return fraction(numer*f.numer,denom*f.denom);
128      }
129     
130      fraction fraction::operator/(const fraction& f) const {
131        return (*this) * (*f);
132      }
133     
134      fraction fraction::operator+(int i) const {
135        return fraction(numer+i*denom,denom);
136      }
137     
138      fraction fraction::operator-(int i) const {
139        return (*this) + -i;
140      }
141     
142      fraction fraction::operator*(int i) const {
143        return fraction(numer*i,denom);
144      }
145     
146      fraction fraction::operator/(int i) const {
147        return fraction(numer,i*denom);
148      }
149     
150      // prefix increment operator
151      fraction& fraction::operator++() {
152          numer += denom;
153          return *this;
154      }
155     
156      // postfix increment operator
157      fraction fraction::operator++(int) {    // Note dummy int argument
158        fraction temp = *this;
159        ++(*this);                // call the prefix operator
160           return temp;               
161      }
162     
163     
164      int main(void)
165      {
166        fraction f(3,4);           // initialize fraction f & g
167        fraction g(1,2);
168        cout << "!f ";  !f;
169        cout << "!g ";  !g;
170        cout << endl;
171        cout << "-g ";  !-g;
172        cout << "*g ";  !*g;
173        fraction h = g + f;
174        cout << endl;
175        cout << "h=g+f " << " !h ";  !h;
176        cout << "!~h ";  !~h;
177        cout << endl;
178        cout << "f+g ";  ! (f + g);
179        cout << "f-g ";  ! (f - g);
180        cout << "f*g ";  ! (f * g);
181        cout << "f/g ";  ! (f / g);
182        cout << endl;
183        cout << "f+=g "; !~(f+=g);
184        cout << "f-=g "; !~(f-=g);
185        cout << "f*=g "; !~(f*=g);
186        cout << "f/=g "; !~(f/=g);
187        cout << endl;
188        cout << "f<g " << (f<g) << endl;
189        cout << "f>g " << (f>g) << endl;
190        cout << "f==g " << (f==g) << endl;
191        cout << "f!=g " << (f!=g) << endl;
192        cout << "f<=g " << (f<=g) << endl;
193        cout << "f>=g " << (f>=g) << endl;
194        cout << endl;
195        cout << "f+5 ";  !(f+5);
196        cout << "f-5 ";  !(f-5);
197        cout << "f*5 ";  !(f*5);
198        cout << "f/5 ";  !(f/5);
199        cout << endl;
200        cout << "f+=5 "; f+=5; cout << "!~f "; !~f;     // What's this?
201        cout << "++f "; !++f; cout << "f="; !f;
202        cout << "f++ "; !f++; cout << "f="; !f;
203     
204        return 0;
205      }


******  Output  ******

!f 3/4
!g 1/2

-g -1/2
*g 2/1

h=g+f  !h 10/8
!~h 5/4

f+g 10/8
f-g 2/8
f*g 3/8
f/g 6/4

f+=g 5/4
f-=g 3/4
f*=g 3/8
f/=g 3/4

f<g 0
f>g 1
f==g 0
f!=g 1
f<=g 0
f>=g 1

f+5 23/4
f-5 -17/4
f*5 15/4
f/5 3/20

f+=5 !~f 23/4
++f 27/4
f=27/4
f++ 27/4
f=31/4

Should any of these member functions be specified as friend functions?

Why do operator~ and unary operator- have different return types?

How do the increment operators work?

Example 6-6 - "More power"

1      // File: ex6-6.cpp
2     
3      #include <iostream>
4      #include <cstdlib>
5      #include <cmath>
6      using namespace std;
7     
8      class Integer
9      {
10        private:
11         long x;
12        public:
13         Integer(long i) { x = i;}
14         long operator^(int);
15      };
16     
17      long Integer::operator^(int power)
18      {
19        if (power == 0) return 1;
20        long temp = x;
21        for (int i = 1; i < power; i++) temp *= x;
22        return temp;
23      }
24     
25     
26      class Real
27      {
28         double d;
29        public:
30         Real(double arg) { d = arg;}
31         double operator^(double);
32      };
33     
34      double Real::operator^(double power)
35      {
36        if (d == 0 && power == 0)
37        {
38          cout << "0 ^ 0 is undefined\n";
39          exit (1);
40        }
41     
42        if (d < 0 && power != floor(power))
43        {
44          cout <<
45              "You may only take integer powers of negative numbers\n";
46          exit (1);
47        }
48     
49       return pow(d,power);
50      }
51      int main (void)
52      {
53        Integer z(2), y(3);
54        cout << (z^5) << endl;
55        cout << (y^0) << endl;
56        Real r1(3.14), r2(6.02e23), r3(1.2345);
57        cout<< (r1^2) << endl;
58        cout<< (r2^3) << endl;
59        cout<< (r3^0) << endl;
60        cout<< (r1^3.14) << endl;
61        Real r4(-1.4);
62        cout << (r4^3) << endl;
63        cout << (r4^1.3) << endl;
64     
65        return 0;
66      }


******  Output  ******

32
1
9.8596
2.18167e+71
1
36.3378
-2.744
You may only take integer powers of negative numbers

What if you want to evaluate an expression like πr2 ?  Is this correct?

3.141592654*r^2

沒有留言:

張貼留言