Bruce Eckel's Thinking in C++, 2nd Ed | Contents | Prev | Next |
//: C12:Unary.cpp // Overloading unary operators #include <iostream> using namespace std; class Integer { long i; Integer* This() { return this; } public: Integer(long ll = 0) : i(ll) {} // No side effects takes const& argument: friend const Integer& operator+(const Integer& a); friend const Integer operator-(const Integer& a); friend const Integer operator~(const Integer& a); friend Integer* operator&(Integer& a); friend int operator!(const Integer& a); // Side effects don't take const& argument: // Prefix: friend const Integer& operator++(Integer& a); // Postfix: friend const Integer operator++(Integer& a, int); // Prefix: friend const Integer& operator--(Integer& a); // Postfix: friend const Integer operator--(Integer& a, int); }; // Global operators: const Integer& operator+(const Integer& a) { cout << "+Integer\n"; return a; // Unary + has no effect } const Integer operator-(const Integer& a) { cout << "-Integer\n"; return Integer(-a.i); } const Integer operator~(const Integer& a) { cout << "~Integer\n"; return Integer(~a.i); } Integer* operator&(Integer& a) { cout << "&Integer\n"; return a.This(); // &a is recursive! } int operator!(const Integer& a) { cout << "!Integer\n"; return !a.i; } // Prefix; return incremented value const Integer& operator++(Integer& a) { cout << "++Integer\n"; a.i++; return a; } // Postfix; return the value before increment: const Integer operator++(Integer& a, int) { cout << "Integer++\n"; Integer r(a.i); a.i++; return r; } // Prefix; return decremented value const Integer& operator--(Integer& a) { cout << "--Integer\n"; a.i--; return a; } // Postfix; return the value before decrement: const Integer operator--(Integer& a, int) { cout << "Integer--\n"; Integer r(a.i); a.i--; return r; } void f(Integer a) { +a; -a; ~a; Integer* ip = &a; !a; ++a; a++; --a; a--; } // Member operators (implicit "this"): class Byte { unsigned char b; public: Byte(unsigned char bb = 0) : b(bb) {} // No side effects: const member function: const Byte& operator+() const { cout << "+Byte\n"; return *this; } const Byte operator-() const { cout << "-Byte\n"; return Byte(-b); } const Byte operator~() const { cout << "~Byte\n"; return Byte(~b); } Byte operator!() const { cout << "!Byte\n"; return Byte(!b); } Byte* operator&() { cout << "&Byte\n"; return this; } // Side effects: non-const member function: const Byte& operator++() { // Prefix cout << "++Byte\n"; b++; return *this; } const Byte operator++(int) { // Postfix cout << "Byte++\n"; Byte before(b); b++; return before; } const Byte& operator--() { // Prefix cout << "--Byte\n"; --b; return *this; } const Byte operator--(int) { // Postfix cout << "Byte--\n"; Byte before(b); --b; return before; } }; void g(Byte b) { +b; -b; ~b; Byte* bp = &b; !b; ++b; b++; --b; b--; } int main() { Integer a; f(a); Byte b; g(b); } ///:~
//: C12:Binary.cpp // Overloading binary operators #include <fstream> #include "../require.h" using namespace std; ofstream out("binary.out"); class Integer { // Combine this with UNARY.CPP long i; public: Integer(long ll = 0) : i(ll) {} // Operators that create new, modified value: friend const Integer operator+(const Integer& left, const Integer& right); friend const Integer operator-(const Integer& left, const Integer& right); friend const Integer operator*(const Integer& left, const Integer& right); friend const Integer operator/(const Integer& left, const Integer& right); friend const Integer operator%(const Integer& left, const Integer& right); friend const Integer operator^(const Integer& left, const Integer& right); friend const Integer operator&(const Integer& left, const Integer& right); friend const Integer operator|(const Integer& left, const Integer& right); friend const Integer operator<<(const Integer& left, const Integer& right); friend const Integer operator>>(const Integer& left, const Integer& right); // Assignments modify & return lvalue: friend Integer& operator+=(Integer& left, const Integer& right); friend Integer& operator-=(Integer& left, const Integer& right); friend Integer& operator*=(Integer& left, const Integer& right); friend Integer& operator/=(Integer& left, const Integer& right); friend Integer& operator%=(Integer& left, const Integer& right); friend Integer& operator^=(Integer& left, const Integer& right); friend Integer& operator&=(Integer& left, const Integer& right); friend Integer& operator|=(Integer& left, const Integer& right); friend Integer& operator>>=(Integer& left, const Integer& right); friend Integer& operator<<=(Integer& left, const Integer& right); // Conditional operators return true/false: friend int operator==(const Integer& left, const Integer& right); friend int operator!=(const Integer& left, const Integer& right); friend int operator<(const Integer& left, const Integer& right); friend int operator>(const Integer& left, const Integer& right); friend int operator<=(const Integer& left, const Integer& right); friend int operator>=(const Integer& left, const Integer& right); friend int operator&&(const Integer& left, const Integer& right); friend int operator||(const Integer& left, const Integer& right); // Write the contents to an ostream: void print(ostream& os) const { os << i; } }; const Integer operator+(const Integer& left, const Integer& right) { return Integer(left.i + right.i); } const Integer operator-(const Integer& left, const Integer& right) { return Integer(left.i - right.i); } const Integer operator*(const Integer& left, const Integer& right) { return Integer(left.i * right.i); } const Integer operator/(const Integer& left, const Integer& right) { require(right.i != 0, "divide by zero"); return Integer(left.i / right.i); } const Integer operator%(const Integer& left, const Integer& right) { require(right.i != 0, "modulo by zero"); return Integer(left.i % right.i); } const Integer operator^(const Integer& left, const Integer& right) { return Integer(left.i ^ right.i); } const Integer operator&(const Integer& left, const Integer& right) { return Integer(left.i & right.i); } const Integer operator|(const Integer& left, const Integer& right) { return Integer(left.i | right.i); } const Integer operator<<(const Integer& left, const Integer& right) { return Integer(left.i << right.i); } const Integer operator>>(const Integer& left, const Integer& right) { return Integer(left.i >> right.i); } // Assignments modify & return lvalue: Integer& operator+=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i += right.i; return left; } Integer& operator-=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i -= right.i; return left; } Integer& operator*=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i *= right.i; return left; } Integer& operator/=(Integer& left, const Integer& right) { require(right.i != 0, "divide by zero"); if(&left == &right) {/* self-assignment */} left.i /= right.i; return left; } Integer& operator%=(Integer& left, const Integer& right) { require(right.i != 0, "modulo by zero"); if(&left == &right) {/* self-assignment */} left.i %= right.i; return left; } Integer& operator^=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i ^= right.i; return left; } Integer& operator&=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i &= right.i; return left; } Integer& operator|=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i |= right.i; return left; } Integer& operator>>=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i >>= right.i; return left; } Integer& operator<<=(Integer& left, const Integer& right) { if(&left == &right) {/* self-assignment */} left.i <<= right.i; return left; } // Conditional operators return true/false: int operator==(const Integer& left, const Integer& right) { return left.i == right.i; } int operator!=(const Integer& left, const Integer& right) { return left.i != right.i; } int operator<(const Integer& left, const Integer& right) { return left.i < right.i; } int operator>(const Integer& left, const Integer& right) { return left.i > right.i; } int operator<=(const Integer& left, const Integer& right) { return left.i <= right.i; } int operator>=(const Integer& left, const Integer& right) { return left.i >= right.i; } int operator&&(const Integer& left, const Integer& right) { return left.i && right.i; } int operator||(const Integer& left, const Integer& right) { return left.i || right.i; } void h(Integer& c1, Integer& c2) { // A complex expression: c1 += c1 * c2 + c2 % c1; #define TRY(OP) \ out << "c1 = "; c1.print(out); \ out << ", c2 = "; c2.print(out); \ out << "; c1 " #OP " c2 produces "; \ (c1 OP c2).print(out); \ out << endl; TRY(+) TRY(-) TRY(*) TRY(/) TRY(%) TRY(^) TRY(&) TRY(|) TRY(<<) TRY(>>) TRY(+=) TRY(-=) TRY(*=) TRY(/=) TRY(%=) TRY(^=) TRY(&=) TRY(|=) TRY(>>=) TRY(<<=) // Conditionals: #define TRYC(OP) \ out << "c1 = "; c1.print(out); \ out << ", c2 = "; c2.print(out); \ out << "; c1 " #OP " c2 produces "; \ out << (c1 OP c2); \ out << endl; TRYC(<) TRYC(>) TRYC(==) TRYC(!=) TRYC(<=) TRYC(>=) TRYC(&&) TRYC(||) } // Member operators (implicit "this"): class Byte { // Combine this with UNARY.CPP unsigned char b; public: Byte(unsigned char bb = 0) : b(bb) {} // No side effects: const member function: const Byte operator+(const Byte& right) const { return Byte(b + right.b); } const Byte operator-(const Byte& right) const { return Byte(b - right.b); } const Byte operator*(const Byte& right) const { return Byte(b * right.b); } const Byte operator/(const Byte& right) const { require(right.b != 0, "divide by zero"); return Byte(b / right.b); } const Byte operator%(const Byte& right) const { require(right.b != 0, "modulo by zero"); return Byte(b % right.b); } const Byte operator^(const Byte& right) const { return Byte(b ^ right.b); } const Byte operator&(const Byte& right) const { return Byte(b & right.b); } const Byte operator|(const Byte& right) const { return Byte(b | right.b); } const Byte operator<<(const Byte& right) const { return Byte(b << right.b); } const Byte operator>>(const Byte& right) const { return Byte(b >> right.b); } // Assignments modify & return lvalue. // operator= can only be a member function: Byte& operator=(const Byte& right) { // Handle self-assignment: if(this == &right) return *this; b = right.b; return *this; } Byte& operator+=(const Byte& right) { if(this == &right) {/* self-assignment */} b += right.b; return *this; } Byte& operator-=(const Byte& right) { if(this == &right) {/* self-assignment */} b -= right.b; return *this; } Byte& operator*=(const Byte& right) { if(this == &right) {/* self-assignment */} b *= right.b; return *this; } Byte& operator/=(const Byte& right) { require(right.b != 0, "divide by zero"); if(this == &right) {/* self-assignment */} b /= right.b; return *this; } Byte& operator%=(const Byte& right) { require(right.b != 0, "modulo by zero"); if(this == &right) {/* self-assignment */} b %= right.b; return *this; } Byte& operator^=(const Byte& right) { if(this == &right) {/* self-assignment */} b ^= right.b; return *this; } Byte& operator&=(const Byte& right) { if(this == &right) {/* self-assignment */} b &= right.b; return *this; } Byte& operator|=(const Byte& right) { if(this == &right) {/* self-assignment */} b |= right.b; return *this; } Byte& operator>>=(const Byte& right) { if(this == &right) {/* self-assignment */} b >>= right.b; return *this; } Byte& operator<<=(const Byte& right) { if(this == &right) {/* self-assignment */} b <<= right.b; return *this; } // Conditional operators return true/false: int operator==(const Byte& right) const { return b == right.b; } int operator!=(const Byte& right) const { return b != right.b; } int operator<(const Byte& right) const { return b < right.b; } int operator>(const Byte& right) const { return b > right.b; } int operator<=(const Byte& right) const { return b <= right.b; } int operator>=(const Byte& right) const { return b >= right.b; } int operator&&(const Byte& right) const { return b && right.b; } int operator||(const Byte& right) const { return b || right.b; } // Write the contents to an ostream: void print(ostream& os) const { os << "0x" << hex << int(b) << dec; } }; void k(Byte& b1, Byte& b2) { b1 = b1 * b2 + b2 % b1; #define TRY2(OP) \ out << "b1 = "; b1.print(out); \ out << ", b2 = "; b2.print(out); \ out << "; b1 " #OP " b2 produces "; \ (b1 OP b2).print(out); \ out << endl; b1 = 9; b2 = 47; TRY2(+) TRY2(-) TRY2(*) TRY2(/) TRY2(%) TRY2(^) TRY2(&) TRY2(|) TRY2(<<) TRY2(>>) TRY2(+=) TRY2(-=) TRY2(*=) TRY2(/=) TRY2(%=) TRY2(^=) TRY2(&=) TRY2(|=) TRY2(>>=) TRY2(<<=) TRY2(=) // Assignment operator // Conditionals: #define TRYC2(OP) \ out << "b1 = "; b1.print(out); \ out << ", b2 = "; b2.print(out); \ out << "; b1 " #OP " b2 produces "; \ out << (b1 OP b2); \ out << endl; b1 = 9; b2 = 47; TRYC2(<) TRYC2(>) TRYC2(==) TRYC2(!=) TRYC2(<=) TRYC2(>=) TRYC2(&&) TRYC2(||) // Chained assignment: Byte b3 = 92; b1 = b2 = b3; } int main() { Integer c1(47), c2(9); h(c1, c2); out << "\n member functions:" << endl; Byte b1(47), b2(9); k(b1, b2); } ///:~
Integer tmp(left.i + right.i); return tmp;
//: C12:Comma.cpp // Overloading the ‘,’ operator #include <iostream> using namespace std; class After { public: const After& operator,(const After&) const { cout << "After::operator,()" << endl; return *this; } }; class Before {}; Before& operator,(int, Before& b) { cout << "Before::operator,()" << endl; return b; } int main() { After a, b; a, b; // Operator comma called Before c; 1, c; // Operator comma called } ///:~
//: C12:Smartp.cpp // Smart pointer example #include <iostream> #include <cstring> using namespace std; class Obj { static int i, j; public: void f() { cout << i++ << endl; } void g() { cout << j++ << endl; } }; // Static member definitions: int Obj::i = 47; int Obj::j = 11; // Container: class ObjContainer { enum { sz = 100 }; Obj* a[sz]; int index; public: ObjContainer() { index = 0; memset(a, 0, sz * sizeof(Obj*)); } void add(Obj* OBJ) { if(index >= sz) return; a[index++] = OBJ; } friend class Sp; }; // Iterator: class Sp { ObjContainer* oc; int index; public: Sp(ObjContainer* objc) { index = 0; oc = objc; } // Return value indicates end of list: int operator++() { // Prefix if(index >= oc->sz) return 0; if(oc->a[++index] == 0) return 0; return 1; } int operator++(int) { // Postfix return operator++(); // Use prefix version } Obj* operator->() const { if(oc->a[index]) return oc->a[index]; static Obj dummy; return &dummy; } }; int main() { const int sz = 10; Obj o[sz]; ObjContainer oc; for(int i = 0; i < sz; i++) oc.add(&o[i]); // Fill it up Sp sp(&oc); // Create an iterator do { sp->f(); // Smart pointer calls sp->g(); } while(sp++); } ///:~
sp->f(); // Smart pointer calls sp->g();