The following is the program I mentioned. I think that it does a nice job of tracing the flow of typecasts and constructors. You may find its output useful in clarifying the discussion on pages 132-133 of your book. I apologize for the lack of comments; I whipped this up rather quickly. I suppose I'll have to add more comments before the term starts. -- Geoff Kuenning geoff@cs.hmc.edu http://fmg-www.cs.ucla.edu/geoff/ It's is not, it isn't ain't, and it's it's, not its, if you mean it is. If you don't, it's its. Then too, it's hers. It isn't her's. It isn't our's either. It's ours, and likewise yours and theirs. -- Oxford University Press, Edpress News ------------------------------cut here------------------------------ #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_ORIGINAL_VERSION #define falseconst #define boxcast int #else // BUDD_ORIGINAL_VERSION #define falseconst const #define boxcast box #endif // BUDD_ORIGINAL_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