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.