我辈岂是蓬蒿人!

C++ && keyWordSpotting

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  11 Posts :: 0 Stories :: 4 Comments :: 0 Trackbacks

常用链接

留言簿(9)

我参与的团队

搜索

  •  

积分与排名

  • 积分 - 6700
  • 排名 - 1379

最新评论

阅读排行榜

评论排行榜

Thinking in C++, 2nd ed. Volume 1

©2000 by Bruce Eckel

Unary operators

The following example shows the syntax to overload all the unary operators, in the form of both global functions (non-member friend functions) and as member functions. These will expand upon the Integer class shown previously and add a new byte class. The meaning of your particular operators will depend on the way you want to use them, but consider the client programmer before doing something unexpected.

Here is a catalog of all the unary functions:


  1 //: C12:OverloadingUnaryOperators.cpp
  2 #include <iostream>
  3 using namespace std;
  4 
  5 // Non-member functions:
  6 class Integer {
  7   long i;
  8   Integer* This() { return this; }
  9 public:
 10   Integer(long ll = 0) : i(ll) {}
 11   // No side effects takes const& argument:
 12   friend const Integer&
 13     operator+(const Integer& a);
 14   friend const Integer
 15     operator-(const Integer& a);
 16   friend const Integer
 17     operator~(const Integer& a);
 18   friend Integer*
 19     operator&(Integer& a);
 20   friend int
 21     operator!(const Integer& a);
 22   // Side effects have non-const& argument:
 23   // Prefix:
 24   friend const Integer&
 25     operator++(Integer& a);
 26   // Postfix:
 27   friend const Integer
 28     operator++(Integer& a, int);
 29   // Prefix:
 30   friend const Integer&
 31     operator--(Integer& a);
 32   // Postfix:
 33   friend const Integer
 34     operator--(Integer& a, int);
 35 };
 36 
 37 // Global operators:
 38 const Integer& operator+(const Integer& a) {
 39   cout << "+Integer\n";
 40   return a; // Unary + has no effect
 41 }
 42 const Integer operator-(const Integer& a) {
 43   cout << "-Integer\n";
 44   return Integer(-a.i);
 45 }
 46 const Integer operator~(const Integer& a) {
 47   cout << "~Integer\n";
 48   return Integer(~a.i);
 49 }
 50 Integer* operator&(Integer& a) {
 51   cout << "&Integer\n";
 52   return a.This(); // &a is recursive!
 53 }
 54 int operator!(const Integer& a) {
 55   cout << "!Integer\n";
 56   return !a.i;
 57 }
 58 // Prefix; return incremented value
 59 const Integer& operator++(Integer& a) {
 60   cout << "++Integer\n";
 61   a.i++;
 62   return a;
 63 }
 64 // Postfix; return the value before increment:
 65 const Integer operator++(Integer& a, int) {
 66   cout << "Integer++\n";
 67   Integer before(a.i);
 68   a.i++;
 69   return before;
 70 }
 71 // Prefix; return decremented value
 72 const Integer& operator--(Integer& a) {
 73   cout << "--Integer\n";
 74   a.i--;
 75   return a;
 76 }
 77 // Postfix; return the value before decrement:
 78 const Integer operator--(Integer& a, int) {
 79   cout << "Integer--\n";
 80   Integer before(a.i);
 81   a.i--;
 82   return before;
 83 }
 84 
 85 // Show that the overloaded operators work:
 86 void f(Integer a) {
 87   +a;
 88   -a;
 89   ~a;
 90   Integer* ip = &a;
 91   !a;
 92   ++a;
 93   a++;
 94   --a;
 95   a--;
 96 }
 97 
 98 // Member functions (implicit "this"):
 99 class Byte {
100   unsigned char b;
101 public:
102   Byte(unsigned char bb = 0) : b(bb) {}
103   // No side effects: const member function:
104   const Byte& operator+() const {
105     cout << "+Byte\n";
106     return *this;
107   }
108   const Byte operator-() const {
109     cout << "-Byte\n";
110     return Byte(-b);
111   }
112   const Byte operator~() const {
113     cout << "~Byte\n";
114     return Byte(~b);
115   }
116   Byte operator!() const {
117     cout << "!Byte\n";
118     return Byte(!b);
119   }
120   Byte* operator&() {
121     cout << "&Byte\n";
122     return this;
123   }
124   // Side effects: non-const member function:
125   const Byte& operator++() { // Prefix
126     cout << "++Byte\n";
127     b++;
128     return *this;
129   }
130   const Byte operator++(int) { // Postfix
131     cout << "Byte++\n";
132     Byte before(b);
133     b++;
134     return before;
135   }
136   const Byte& operator--() { // Prefix
137     cout << "--Byte\n";
138     --b;
139     return *this;
140   }
141   const Byte operator--(int) { // Postfix
142     cout << "Byte--\n";
143     Byte before(b);
144     --b;
145     return before;
146   }
147 };
148 
149 void g(Byte b) {
150   +b;
151   -b;
152   ~b;
153   Byte* bp = &b;
154   !b;
155   ++b;
156   b++;
157   --b;
158   b--;
159 }
160 
161 int main() {
162   Integer a;
163   f(a);
164   Byte b;
165   g(b);
166 ///:~
167 

The functions are grouped according to the way their arguments are passed. Guidelines for how to pass and return arguments are given later. The forms above (and the ones that follow in the next section) are typically what you’ll use, so start with them as a pattern when overloading your own operators.

Binary operators

The following listing repeats the example of OverloadingUnaryOperators.cpp for binary operators so you have an example of all the operators you might want to overload. Again, both global versions and member function versions are shown.

  1 //: C12:Integer.h
  2 // Non-member overloaded operators
  3 #ifndef INTEGER_H
  4 #define INTEGER_H
  5 #include <iostream>
  6 
  7 // Non-member functions:
  8 class Integer { 
  9   long i;
 10 public:
 11   Integer(long ll = 0) : i(ll) {}
 12   // Operators that create new, modified value:
 13   friend const Integer
 14     operator+(const Integer& left,
 15               const Integer& right);
 16   friend const Integer
 17     operator-(const Integer& left,
 18               const Integer& right);
 19   friend const Integer
 20     operator*(const Integer& left,
 21               const Integer& right);
 22   friend const Integer
 23     operator/(const Integer& left,
 24               const Integer& right);
 25   friend const Integer
 26     operator%(const Integer& left,
 27               const Integer& right);
 28   friend const Integer
 29     operator^(const Integer& left,
 30               const Integer& right);
 31   friend const Integer
 32     operator&(const Integer& left,
 33               const Integer& right);
 34   friend const Integer
 35     operator|(const Integer& left,
 36               const Integer& right);
 37   friend const Integer
 38     operator<<(const Integer& left,
 39                const Integer& right);
 40   friend const Integer
 41     operator>>(const Integer& left,
 42                const Integer& right);
 43   // Assignments modify & return lvalue:
 44   friend Integer&
 45     operator+=(Integer& left,
 46                const Integer& right);
 47   friend Integer&
 48     operator-=(Integer& left,
 49                const Integer& right);
 50   friend Integer&
 51     operator*=(Integer& left,
 52                const Integer& right);
 53   friend Integer&
 54     operator/=(Integer& left,
 55                const Integer& right);
 56   friend Integer&
 57     operator%=(Integer& left,
 58                const Integer& right);
 59   friend Integer&
 60     operator^=(Integer& left,
 61                const Integer& right);
 62   friend Integer&
 63     operator&=(Integer& left,
 64                const Integer& right);
 65   friend Integer&
 66     operator|=(Integer& left,
 67                const Integer& right);
 68   friend Integer&
 69     operator>>=(Integer& left,
 70                 const Integer& right);
 71   friend Integer&
 72     operator<<=(Integer& left,
 73                 const Integer& right);
 74   // Conditional operators return true/false:
 75   friend int
 76     operator==(const Integer& left,
 77                const Integer& right);
 78   friend int
 79     operator!=(const Integer& left,
 80                const Integer& right);
 81   friend int
 82     operator<(const Integer& left,
 83               const Integer& right);
 84   friend int
 85     operator>(const Integer& left,
 86               const Integer& right);
 87   friend int
 88     operator<=(const Integer& left,
 89                const Integer& right);
 90   friend int
 91     operator>=(const Integer& left,
 92                const Integer& right);
 93   friend int
 94     operator&&(const Integer& left,
 95                const Integer& right);
 96   friend int
 97     operator||(const Integer& left,
 98                const Integer& right);
 99   // Write the contents to an ostream:
100   void print(std::ostream& os) const { os << i; }
101 }; 
102 #endif // INTEGER_H ///:~
103 //: C12:Integer.cpp {O}
104 // Implementation of overloaded operators
105 #include "Integer.h"
106 #include "../require.h"
107 
108 const Integer
109   operator+(const Integer& left,
110             const Integer& right) {
111   return Integer(left.i + right.i);
112 }
113 const Integer
114   operator-(const Integer& left,
115             const Integer& right) {
116   return Integer(left.i - right.i);
117 }
118 const Integer
119   operator*(const Integer& left,
120             const Integer& right) {
121   return Integer(left.i * right.i);
122 }
123 const Integer
124   operator/(const Integer& left,
125             const Integer& right) {
126   require(right.i != 0"divide by zero");
127   return Integer(left.i / right.i);
128 }
129 const Integer
130   operator%(const Integer& left,
131             const Integer& right) {
132   require(right.i != 0"modulo by zero");
133   return Integer(left.i % right.i);
134 }
135 const Integer
136   operator^(const Integer& left,
137             const Integer& right) {
138   return Integer(left.i ^ right.i);
139 }
140 const Integer
141   operator&(const Integer& left,
142             const Integer& right) {
143   return Integer(left.i & right.i);
144 }
145 const Integer
146   operator|(const Integer& left,
147             const Integer& right) {
148   return Integer(left.i | right.i);
149 }
150 const Integer
151   operator<<(const Integer& left,
152              const Integer& right) {
153   return Integer(left.i << right.i);
154 }
155 const Integer
156   operator>>(const Integer& left,
157              const Integer& right) {
158   return Integer(left.i >> right.i);
159 }
160 // Assignments modify & return lvalue:
161 Integer& operator+=(Integer& left,
162                     const Integer& right) {
163    if(&left == &right) {/* self-assignment */}
164    left.i += right.i;
165    return left;
166 }
167 Integer& operator-=(Integer& left,
168                     const Integer& right) {
169    if(&left == &right) {/* self-assignment */}
170    left.i -= right.i;
171    return left;
172 }
173 Integer& operator*=(Integer& left,
174                     const Integer& right) {
175    if(&left == &right) {/* self-assignment */}
176    left.i *= right.i;
177    return left;
178 }
179 Integer& operator/=(Integer& left,
180                     const Integer& right) {
181    require(right.i != 0"divide by zero");
182    if(&left == &right) {/* self-assignment */}
183    left.i /= right.i;
184    return left;
185 }
186 Integer& operator%=(Integer& left,
187                     const Integer& right) {
188    require(right.i != 0"modulo by zero");
189    if(&left == &right) {/* self-assignment */}
190    left.i %= right.i;
191    return left;
192 }
193 Integer& operator^=(Integer& left,
194                     const Integer& right) {
195    if(&left == &right) {/* self-assignment */}
196    left.i ^= right.i;
197    return left;
198 }
199 Integer& operator&=(Integer& left,
200                     const Integer& right) {
201    if(&left == &right) {/* self-assignment */}
202    left.i &= right.i;
203    return left;
204 }
205 Integer& operator|=(Integer& left,
206                     const Integer& right) {
207    if(&left == &right) {/* self-assignment */}
208    left.i |= right.i;
209    return left;
210 }
211 Integer& operator>>=(Integer& left,
212                      const Integer& right) {
213    if(&left == &right) {/* self-assignment */}
214    left.i >>= right.i;
215    return left;
216 }
217 Integer& operator<<=(Integer& left,
218                      const Integer& right) {
219    if(&left == &right) {/* self-assignment */}
220    left.i <<= right.i;
221    return left;
222 }
223 // Conditional operators return true/false:
224 int operator==(const Integer& left,
225                const Integer& right) {
226     return left.i == right.i;
227 }
228 int operator!=(const Integer& left,
229                const Integer& right) {
230     return left.i != right.i;
231 }
232 int operator<(const Integer& left,
233               const Integer& right) {
234     return left.i < right.i;
235 }
236 int operator>(const Integer& left,
237               const Integer& right) {
238     return left.i > right.i;
239 }
240 int operator<=(const Integer& left,
241                const Integer& right) {
242     return left.i <= right.i;
243 }
244 int operator>=(const Integer& left,
245                const Integer& right) {
246     return left.i >= right.i;
247 }
248 int operator&&(const Integer& left,
249                const Integer& right) {
250     return left.i && right.i;
251 }
252 int operator||(const Integer& left,
253                const Integer& right) {
254     return left.i || right.i;
255 ///:~
256 //: C12:IntegerTest.cpp
257 //{L} Integer
258 #include "Integer.h"
259 #include <fstream>
260 using namespace std;
261 ofstream out("IntegerTest.out");
262 
263 void h(Integer& c1, Integer& c2) {
264   // A complex expression:
265   c1 += c1 * c2 + c2 % c1;
266   #define TRY(OP) \
267     out << "c1 = "; c1.print(out); \
268     out << ", c2 = "; c2.print(out); \
269     out << ";  c1 " #OP " c2 produces "; \
270     (c1 OP c2).print(out); \
271     out << endl;
272   TRY(+) TRY(-) TRY(*) TRY(/)
273   TRY(%) TRY(^) TRY(&) TRY(|)
274   TRY(<<) TRY(>>) TRY(+=) TRY(-=)
275   TRY(*=) TRY(/=) TRY(%=) TRY(^=)
276   TRY(&=) TRY(|=) TRY(>>=) TRY(<<=)
277   // Conditionals:
278   #define TRYC(OP) \
279     out << "c1 = "; c1.print(out); \
280     out << ", c2 = "; c2.print(out); \
281     out << ";  c1 " #OP " c2 produces "; \
282     out << (c1 OP c2); \
283     out << endl;
284   TRYC(<) TRYC(>) TRYC(==) TRYC(!=) TRYC(<=)
285   TRYC(>=) TRYC(&&) TRYC(||)
286 
287 
288 int main() {
289   cout << "friend functions" << endl;
290   Integer c1(47), c2(9);
291   h(c1, c2);
292 ///:~
293 //: C12:Byte.h
294 // Member overloaded operators
295 #ifndef BYTE_H
296 #define BYTE_H
297 #include "../require.h"
298 #include <iostream>
299 // Member functions (implicit "this"):
300 class Byte { 
301   unsigned char b;
302 public:
303   Byte(unsigned char bb = 0) : b(bb) {}
304   // No side effects: const member function:
305   const Byte
306     operator+(const Byte& right) const {
307     return Byte(b + right.b);
308   }
309   const Byte
310     operator-(const Byte& right) const {
311     return Byte(b - right.b);
312   }
313   const Byte
314     operator*(const Byte& right) const {
315     return Byte(b * right.b);
316   }
317   const Byte
318     operator/(const Byte& right) const {
319     require(right.b != 0"divide by zero");
320     return Byte(b / right.b);
321   }
322   const Byte
323     operator%(const Byte& right) const {
324     require(right.b != 0"modulo by zero");
325     return Byte(b % right.b);
326   }
327   const Byte
328     operator^(const Byte& right) const {
329     return Byte(b ^ right.b);
330   }
331   const Byte
332     operator&(const Byte& right) const {
333     return Byte(b & right.b);
334   }
335   const Byte
336     operator|(const Byte& right) const {
337     return Byte(b | right.b);
338   }
339   const Byte
340     operator<<(const Byte& right) const {
341     return Byte(b << right.b);
342   }
343   const Byte
344     operator>>(const Byte& right) const {
345     return Byte(b >> right.b);
346   }
347   // Assignments modify & return lvalue.
348   // operator= can only be a member function:
349   Byte& operator=(const Byte& right) {
350     // Handle self-assignment:
351     if(this == &right) return *this;
352     b = right.b;
353     return *this;
354   }
355   Byte& operator+=(const Byte& right) {
356     if(this == &right) {/* self-assignment */}
357     b += right.b;
358     return *this;
359   }
360   Byte& operator-=(const Byte& right) {
361     if(this == &right) {/* self-assignment */}
362     b -= right.b;
363     return *this;
364   }
365   Byte& operator*=(const Byte& right) {
366     if(this == &right) {/* self-assignment */}
367     b *= right.b;
368     return *this;
369   }
370   Byte& operator/=(const Byte& right) {
371     require(right.b != 0"divide by zero");
372     if(this == &right) {/* self-assignment */}
373     b /= right.b;
374     return *this;
375   }
376   Byte& operator%=(const Byte& right) {
377     require(right.b != 0"modulo by zero");
378     if(this == &right) {/* self-assignment */}
379     b %= right.b;
380     return *this;
381   }
382   Byte& operator^=(const Byte& right) {
383     if(this == &right) {/* self-assignment */}
384     b ^= right.b;
385     return *this;
386   }
387   Byte& operator&=(const Byte& right) {
388     if(this == &right) {/* self-assignment */}
389     b &= right.b;
390     return *this;
391   }
392   Byte& operator|=(const Byte& right) {
393     if(this == &right) {/* self-assignment */}
394     b |= right.b;
395     return *this;
396   }
397   Byte& operator>>=(const Byte& right) {
398     if(this == &right) {/* self-assignment */}
399     b >>= right.b;
400     return *this;
401   }
402   Byte& operator<<=(const Byte& right) {
403     if(this == &right) {/* self-assignment */}
404     b <<= right.b;
405     return *this;
406   }
407   // Conditional operators return true/false:
408   int operator==(const Byte& right) const {
409       return b == right.b;
410   }
411   int operator!=(const Byte& right) const {
412       return b != right.b;
413   }
414   int operator<(const Byte& right) const {
415       return b < right.b;
416   }
417   int operator>(const Byte& right) const {
418       return b > right.b;
419   }
420   int operator<=(const Byte& right) const {
421       return b <= right.b;
422   }
423   int operator>=(const Byte& right) const {
424       return b >= right.b;
425   }
426   int operator&&(const Byte& right) const {
427       return b && right.b;
428   }
429   int operator||(const Byte& right) const {
430       return b || right.b;
431   }
432   // Write the contents to an ostream:
433   void print(std::ostream& os) const {
434     os << "0x" << std::hex << int(b) << std::dec;
435   }
436 }; 
437 #endif // BYTE_H ///:~
438 //: C12:ByteTest.cpp
439 #include "Byte.h"
440 #include <fstream>
441 using namespace std;
442 ofstream out("ByteTest.out");
443 
444 void k(Byte& b1, Byte& b2) {
445   b1 = b1 * b2 + b2 % b1;
446 
447   #define TRY2(OP) \
448     out << "b1 = "; b1.print(out); \
449     out << ", b2 = "; b2.print(out); \
450     out << ";  b1 " #OP " b2 produces "; \
451     (b1 OP b2).print(out); \
452     out << endl;
453 
454   b1 = 9; b2 = 47;
455   TRY2(+) TRY2(-) TRY2(*) TRY2(/)
456   TRY2(%) TRY2(^) TRY2(&) TRY2(|)
457   TRY2(<<) TRY2(>>) TRY2(+=) TRY2(-=)
458   TRY2(*=) TRY2(/=) TRY2(%=) TRY2(^=)
459   TRY2(&=) TRY2(|=) TRY2(>>=) TRY2(<<=)
460   TRY2(=// Assignment operator
461 
462   // Conditionals:
463   #define TRYC2(OP) \
464     out << "b1 = "; b1.print(out); \
465     out << ", b2 = "; b2.print(out); \
466     out << ";  b1 " #OP " b2 produces "; \
467     out << (b1 OP b2); \
468     out << endl;
469 
470   b1 = 9; b2 = 47;
471   TRYC2(<) TRYC2(>) TRYC2(==) TRYC2(!=) TRYC2(<=)
472   TRYC2(>=) TRYC2(&&) TRYC2(||)
473 
474   // Chained assignment:
475   Byte b3 = 92;
476   b1 = b2 = b3;
477 }
478 
479 int main() {
480   out << "member functions:" << endl;
481   Byte b1(47), b2(9);
482   k(b1, b2);
483 ///:~
484 

You can see that operator= is only allowed to be a member function. This is explained later.

Notice that all of the assignment operators have code to check for self-assignment; this is a general guideline. In some cases this is not necessary; for example, with operator+= you often want to say A+=A and have it add A to itself. The most important place to check for self-assignment is operator= because with complicated objects disastrous results may occur. (In some cases it’s OK, but you should always keep it in mind when writing operator=.)

All of the operators shown in the previous two examples are overloaded to handle a single type. It’s also possible to overload operators to handle mixed types, so you can add apples to oranges, for example. Before you start on an exhaustive overloading of operators, however, you should look at the section on automatic type conversion later in this chapter. Often, a type conversion in the right place can save you a lot of overloaded operators.

posted on 2006-08-17 12:14 keyws 阅读(574) 评论(0)  编辑 收藏 引用 所属分类: std C++ topic

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理