#include #if 0 /* * Budd's code */ class box { public: box() { value = 0; } box(int i) { value = i; } box(box& a) { value = a.value; } ~box() {} void operator=(box& right) { value = right.value; } operator int() { return value; } private: int value; }; box operator+(box& left, box& right) { return box((int)left + (int)right); } int foo(box abox) { box bbox; bbox = abox + 1; return bbox; } int main() { box mybox(3); mybox = 4; mybox = foo(mybox + 1); return 0; } #else /* * Class for managing indentation. Create an indentor() at the * beginning of a block, and call indentor::indent(stream) to produce * indentation on the stream. */ class Indenter { public: Indenter(); ~Indenter(); static void indent(ostream& stream, int offset = 0); private: enum { increment = 2 }; static int indentation; }; int Indenter::indentation = 0; Indenter::Indenter() { indentation += increment; } Indenter::~Indenter() { indentation -= increment; } void Indenter::indent( ostream& stream, int offset) { for (int i = -offset * increment; i < indentation; i++) stream << ' '; } /* * Class for tracking the life of a function. */ class FunctionTracker { public: FunctionTracker(const char* functionName); ~FunctionTracker(); private: Indenter indenter; const char* name; }; FunctionTracker::FunctionTracker( const char* functionName) : indenter(), name(functionName) { Indenter::indent(cerr, -1); cerr << "entered function " << name << '\n'; } FunctionTracker::~FunctionTracker() { Indenter::indent(cerr, -1); cerr << "leaving function " << name << '\n'; } /* * Class for tracking the life of a class. Derive from this class to * have your class automatically tracked and reported. */ class ClassTracker { public: ClassTracker(); ClassTracker(const ClassTracker& source); ~ClassTracker(); const ClassTracker& operator=(const ClassTracker& source); int id() const; int source() const; private: const int uniqueID; int sourceID; static int nextID; }; int ClassTracker::nextID = 0; ClassTracker::ClassTracker() : uniqueID(++nextID), sourceID(0) { Indenter::indent(cerr); cerr << "class instance " << uniqueID << " created from scratch\n"; } ClassTracker::ClassTracker(const ClassTracker& source) : uniqueID(++nextID), sourceID(source.uniqueID) { Indenter::indent(cerr); cerr << "class instance " << uniqueID << " created by copying instance " << sourceID << '\n'; } ClassTracker::~ClassTracker() { Indenter::indent(cerr); cerr << "destroyed class instance " << uniqueID << '\n'; } const ClassTracker& ClassTracker::operator=(const ClassTracker& source) { sourceID = source.uniqueID; Indenter::indent(cerr); cerr << "class instance " << uniqueID << " assigned from instance " << sourceID << '\n'; return *this; } int ClassTracker::id() const { return uniqueID; } int ClassTracker::source() const { return sourceID; } /* * Preprocessor function for tracking statement execution. You can * replace the "code" argument with any legal C++ code, and the macro * will first write the code to stderr and then execute it. * * WARNING: If the "X" macro is used as the body of a control * statement (if, for, while, or do-while), then it must be enclosed * in curly braces. */ #define X(code) cerr << "\t\t" # code << "\n"; code /* * Slightly modified version of Budd's code that generates tracking * information. * * There are two related problems with Budd's original code that will * make it fail to work as described in the book. First, if the + * operator is defined as taking constant operands (which can be done * by defining "falseconst" as const), then you will get errors * because the compiler can't decide whether to convert one operand to * a box and add two boxes, or convert the other operand to an integer * and add two integers. Second, if falseconst is defined as nothing * (null) and boxcast is defined as "int", then the compiler will * make the latter choice (converting the box operand to integer and * adding the integers). This decision is precisely the opposite of * what Budd intended in the book. * * To get the effect expected in the book, explicit typecasts must be * used. These can be accomplished by defining boxcast as box. */ #ifdef BUDD_BROKEN_VERSION #define falseconst #define boxcast int #else // BUDD_BROKEN_VERSION #define falseconst const #define boxcast box #endif // BUDD_BROKEN_VERSION class box : public ClassTracker { public: box(); box(int i); box(const box& a); ~box(); void operator=(const box& right); operator int() const; private: int value; }; box::box() : value(0) { Indenter x; Indenter::indent(cerr); cerr << "default constructor\n"; } box::box( int i) : value(i) { Indenter x; Indenter::indent(cerr); cerr << "constructed with argument " << i << '\n'; } box::box( const box& a) : value(a.value) { Indenter x; Indenter::indent(cerr); cerr << "constructed with argument " << value << '\n'; } box::~box() { } void box::operator=( const box& right) { (ClassTracker&)*this = (const ClassTracker&)right; value = right.value; } box::operator int() const { Indenter x; Indenter::indent(cerr); cerr << "converting class instance " << id() << " to integer (value " << value << ")\n"; return value; } box operator+(falseconst box& left, falseconst box& right) { FunctionTracker x("operator+(box&, box&)"); Indenter::indent(cerr); cerr << "adding instances " << left.id() << " and " << right.id() << '\n'; return box((int)left + (int)right); } int foo(box abox) { FunctionTracker x("foo"); X(box bbox); X(bbox = abox + (boxcast)1); X(return bbox); } int main() { X(box mybox(3)); X(mybox = 4); X(mybox = foo(mybox + (boxcast)1)); X(return 0); } #endif