#ifndef FOO_INCLUDE #define FOO_INCLUDE #include /** This example code is my attempt to manage the creation and destruction of objects for easy extension and inheritance. */ class FooBase { private: // Always save data members as pointers, not references. std::string * _data; // data is always private protected: static const int MaxLength = 10; // Internal constant FooBase () // Default constructor for derived classes { init (); } void init () // Never virtual. { _data = 0; // Initialize all data to defaults. } // Init methods allow derived classes to delay construction. void init (const std::string & data) { init (); // Allows safe destruction after exception if (0 == data.length () || MaxLength < data.length ()) { // check args throw BadArg (); } _data = new std::string (data); } // Dispose methods free resources. void dispose () throw () { // Don't throw exception when out of scope if (_data) { // Make sure constructor finished delete _data; // Frees memory } _data = 0; // Make sure this can be called twice. } // Derived class uses protected accessors and members remain private. virtual std::string * getData () const { return _data; } public: struct BadArg {}; // Use unique types for exceptions. explicit // "explicit" avoids accidental type conversion FooBase (const std::string & data) // User's constructor. { init (data); // Constructors share init methods. } explicit FooBase (const char *data) // Alternate constructor { init (std::string (data)); // Constructors share init methods. } virtual ~ FooBase () { // Always virtual for derived classes. dispose(); } virtual int getLength () const { return _data-> length (); } virtual FooBase * clone () const // Prefer to copy constructor. { return new FooBase (*_data); } private: // Hide or override default shallow copy of copy constructor and assignment FooBase (const FooBase &that) { init(*that._data); }; FooBase & operator= (const FooBase &that) { if (this == &that) { return *this; } dispose(); // free existing resources init(*that._data); return *this; } }; // Example of a derived class class FooChild: public FooBase // Base classes always public { private: mutable int _calls; // Additional data not of logical state protected: FooChild () // May add another derived class later { init (); } void init () // Safe defaults for everything { FooBase::init (); _calls = 0; } void init (const std::string & data) // New init method invokes old { init (); // Not already called if (0 == data.length ()) { throw BadArg (); } std::string longerData (data); // Massage argument longerData.append ("1234"); FooBase::init (longerData); // Finish initializing base } void dispose() { FooBase::dispose(); _calls = 0; // not really necessary } public: explicit FooChild (const std::string & data) { init (data); } explicit FooChild (const char *data) { init (std::string (data)); } virtual int getLength () const // "Enhance" parent method { ++ _calls; // Saving statistics, but logically const return FooBase::getLength (); // Parent finishes the job. } virtual int getCalls () const // Get calling statistics { return _calls; } virtual FooChild * clone () const // Overload with derived return type. { return new FooChild(*this); } virtual ~ FooChild () // Base destructor is called automatically { dispose(); } private: FooChild (const FooChild &that) { // hide default shallow copy FooBase::init (*that.getData ()); this->_calls = that._calls; } FooChild & operator= (const FooChild &that) { // hide default shallow copy if (this == &that) { return *this; } dispose(); FooBase::init (*that.getData ()); this->_calls = that._calls; } }; #endif