home *** CD-ROM | disk | FTP | other *** search
- //----------------------------------------------------------------------------//
- // (c) 1994 Larry Morley, All Rights Reserved. //
- // For non-commercial use only without express written permission of author. //
- //----------------------------------------------------------------------------//
- // //
- // My standard disclaimer, terms and conditions apply, and are available //
- // upon request. By using this information you agree to the aforementioned //
- // terms and conditions. Basically, they just cover my hide. //
- // //
- // I can be reached at CompuServe 73670,563 or by mail at //
- // //
- // 6909 Custer #2503 //
- // Plano, TX 75023 //
- // //
- // if you need licensing information for commercial use; or, if you have some //
- // feedback or code you've developed and would like to pass along and/or get //
- // a critique on, or if you're having some trouble writing C++ apps. Don't //
- // hesitate to contact me. I'll be of as much help as I can. //
- // //
- // PLEASE send me your thoughts and comments. Thanks. //
- // -Larry //
- //----------------------------------------------------------------------------//
- // It's difficult to enter into a discussion on OOP without someone bringing //
- // up SmallTalk. One of it's supposed selling points besides being OO by //
- // nature over C++ is that EVERYTHING, including numbers, letters, etc. is //
- // represented as an object. A lot of folks don't realize it, but C++ has //
- // the same capability. I'm presenting here, for you, a way to program //
- // C++ using almost only objects (one exception is the implementation of //
- // the classes presented here). The first, bottom most class is called //
- // GenericObject. It contains a value, a class name, the size of the //
- // object (in aribtrary units - sizeof(char) is used in this implementation), //
- // a count of how many times the object's been referenced, and a field //
- // of flags that can be set, cleared and tested. The reference counters //
- // are useful for several purposes; one is debugging, another is controlling //
- // resource usage. //
- // //
- // NOTE: The "void *" type of value is intended to be used as a catch-all //
- // value; i.e., pointers to structs, classes, etc. //
- // //
- // The next class is "Integer". These objects looka and function like "int"s //
- // to other functions, in expressions, etc. BUT are actually objects/ //
- // //
- // One thing to note is that while this is a nice, solid object model I'm //
- // incurring a large amount of overhead. That's the OOP tradeoff sometimes; //
- // the more object oriented and accurate your model, the more you accumulate //
- // extra (extra in that it wouldn't be present using native types and //
- // operators. But, there's inarguably tremendous benefits in all areas of //
- // the development process for reasonably pure OOP. And, this implementaion //
- // is as close to pure object oriented programming as you're ever going to //
- // get. //
- //----------------------------------------------------------------------------//
- // //
- // Summary of GenericObject class methods: //
- // //
- // *********************** //
- // ***Protected Methods*** //
- // *********************** //
- // //
- // Object internal common initialization code: //
- // //
- // void GlobalObjectInit() //
- // //
- // Bitmask manipulation routines: //
- // //
- // (1) Turn a bit on; returns new flags. //
- // unsigned long SetBit (unsigned long lMask) //
- // (2) Test bit status (logical AND); returns zero or one //
- // unsigned long TestBit (unsigned long lMask) //
- // (3) Turn a bit off; returns new flags. //
- // unsigned long ClearBit(unsigned long lMask) //
- // //
- // ************************* //
- // *** Public Methods *** //
- // ***Class Contstructors*** //
- // ************************* //
- // //
- // (1) Generic object, no type or size supplied. //
- // GenericObject(void ) //
- // //
- // (2) Constructor for object with data type of "char" //
- // GenericObject(char ) //
- // //
- // (3) Constructor for object with data type of "unsigned char" //
- // GenericObject(unsigned char) //
- // //
- // (4) Constructor for object with data type of "int" //
- // GenericObject(int ) //
- // //
- // (5) Constructor for object with data type of "unsigned int" //
- // GenericObject(unsigned int ) //
- // //
- // (6) Constructor for object with data type of "long" //
- // GenericObject(long ) //
- // //
- // (7) Constructor for object with data type of "unsigned long" //
- // GenericObject(unsigned long) //
- // //
- // (8) Char pointer, no size given. Size of object = physical size of //
- // pointer in SizeBasis units. //
- // GenericObject(char * ) //
- // //
- // (9) Char pointer, size supplied. Size of object = supplied size. //
- // GenericObject(char *initialValue, int initialSize) //
- // //
- // (10) Void pointer, no size given. Size of object = physical size of //
- // pointer in SizeBasis units. //
- // GenericObject(void * ) //
- // //
- // (11) Void pointer, size supplied. Size of object = supplied size. //
- // GenericObject(void *initialValue, int initialSize) //
- // //
- // *************************** //
- // ***Miscellaneous Methods*** //
- // *************************** //
- // //
- // (1) Return the name of the current class: //
- // char *GetClassName() //
- // //
- // Function doesn't need to be virtual as long as each derived //
- // class defines a protected data member "char *szClassName"; //
- // the derived classes declaration is dominant. //
- // //
- // (2) Increment object's reference count: //
- // int ReferenceObject() //
- // //
- // (3) Decrement object's reference count: //
- // int DeReferenceObject() //
- // //
- // (4) Get / Set Object Size: //
- // int &ObjectSize() //
- // //
- // (5) Get / Set reference count: //
- // int &ReferenceCount() //
- // //
- // (6) Get / Set maximum reference count: //
- // int &MaxReferenceCount() //
- // //
- // ****************** //
- // ***Value Method*** //
- // ****************** //
- // //
- // Get Object's value in the form of a GenericDataType type: //
- // GenericDataType &ObjectValue() //
- // //
- // ************************** //
- // ***Conversion Functions*** //
- // ************************** //
- // //
- // Provided here so derived classes don't need to define their own set //
- // of conversions to intrinsic data types. //
- // //
- // Conversion to "char": //
- // operator char() //
- // //
- // Conversion to "unsigned char": //
- // operator unsigned char() //
- // //
- // Conversion to "int": //
- // operator int() //
- // //
- // Conversion to "unsigned int": //
- // operator unsigned int() //
- // //
- // Conversion to "long": //
- // operator long() //
- // //
- // Conversion to "unsigned long": //
- // operator unsigned long() //
- // //
- // Conversion to "char *": //
- // operator char *() //
- // //
- // Conversion to "void *" (See note above on use of the void * type): //
- // operator void *() //
- // //
- //----------------------------------------------------------------------------//
- // //
- //If you want to build the sample main(), remove the comment operator (//)
- //from the line below:
- #define __BUILD_SAMPLE__
-
- //============================================================================//
- // Define what units to base object size on (sizeof(char) is used; under OS/2
- // it should be equivalent to bytes).
- #define SizeBasis (sizeof(char))
-
- // Define a generic data type
- typedef union
- {
- char cValue;
- unsigned char ucValue;
- int iValue;
- unsigned int uiValue;
- long lValue;
- unsigned long ulValue;
- char * szValue;
- void * pvValue; // Struct, class, etc.
- } GenericDataType;
-
- //============================================================================//
- // Define a generic object class
- class GenericObject
- {
-
- protected:
-
- // Name of this class (text, set by
- // common initialization routine)
- char *szClassName;
-
-
- // The object's value
- GenericDataType objValue;
-
- //-------------------------------
- // Flags with meanings
- // defined elsewhere
- unsigned long ulFlagBits;
-
- //-------------------------------
- // Define the max number of times
- // object can be referenced
- // (0 -> no limit)
- int iMaxReferenceCount;
-
- //-------------------------------
- // Keep track of how many times
- // the object's in use
- int iReferenceCount;
-
- //-------------------------------
- // Size of the object in
- // "SizeBasis" units. NOTE: In
- // the cases where a constructor
- // takes a pointer as an argument,
- // without a specified size, the
- // size IS THE SIZE OF THE
- // POINTER, NOT the data it
- // points to. Beware.
- int iObjectSize;
-
- //-------------------------------
- // Common initialization routine
- // Do early on in constructor
- // so iMaxReferenceCount can
- // be set if desired (and
- // a constructor to set it
- // is provided).
- void GlobalObjectInit()
- {
-
- szClassName = "Base_Generic_Object";
-
- ulFlagBits = 0UL;
- iReferenceCount = 0;
- iMaxReferenceCount = 0;
- iObjectSize = 0;
-
- objValue.cValue = (char)0;
- objValue.ucValue = (unsigned char)0;
- objValue.iValue = 0;
- objValue.uiValue = 0;
- objValue.lValue = 0L;
- objValue.ulValue = 0UL;
- objValue.szValue = (char *)0;
- objValue.pvValue = (void *)0;
-
- return;
- }
-
- //-------------------------------
- // Turn a bit on, off, or test it -
- // keep these members protected to
- // force derived classes to create
- // a meaningful API.
- unsigned long SetBit(unsigned long lMask)
- {
- return (ulFlagBits | lMask);
- }
-
- //-------------------------------
- // Test a bit in the bit flags
- unsigned long TestBit(unsigned long lMask)
- {
- return (ulFlagBits & lMask);
- }
-
- //-------------------------------
- // Clear a bit in the bit flags
- unsigned long ClearBit(unsigned long lMask)
- {
- return (ulFlagBits & (~lMask));
- }
-
- //------------------------------------------------------
-
- public:
-
- //------------------------------------------
- // Constructors:
- // No initial type or value:
- GenericObject()
- {
- // Do common initialization only
- // (nothing else to do)
- GlobalObjectInit();
- }
-
- //------------------------------------------
- // "char" object:
- GenericObject(char initialValue)
- {
- // Do common initialization
- GlobalObjectInit();
- // Specific initialization
- objValue.cValue = initialValue;
- // Set the object's size
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //------------------------------------------
- // "unsigned char" object:
- GenericObject(unsigned char initialValue)
- {
- GlobalObjectInit();
- objValue.ucValue = initialValue;
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //------------------------------------------
- // "int" object:
- GenericObject(int initialValue )
- {
- GlobalObjectInit();
- objValue.iValue = initialValue;
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //------------------------------------------
- // "unsigned int" object:
- GenericObject(unsigned int initialValue)
- {
- GlobalObjectInit();
- objValue.uiValue = initialValue;
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //------------------------------------------
- // "long" object:
- GenericObject(long initialValue)
- {
- GlobalObjectInit();
- objValue.lValue = initialValue;
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //------------------------------------------
- // "unsigned long" object:
- GenericObject(unsigned long initialValue)
- {
- GlobalObjectInit();
- objValue.ulValue = initialValue;
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //------------------------------------------
- // "char *" object:
- // NOTE: no actual copy of the "char *"
- // or string is made; the constructor
- // simply stores the address.
- // An actual copy can be made using
- // the value methods.
- GenericObject(char * initialValue)
- {
- GlobalObjectInit();
- objValue.szValue = initialValue;
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //-----------------------------------------
- // "char *" object with size specified:
- GenericObject(char *initialValue, int initialSize)
- {
- GlobalObjectInit();
- objValue.szValue = initialValue;
- // Use supplied size
- iObjectSize = initialSize;
- }
-
- //-----------------------------------------
- // "void *" object:
- GenericObject(void * initialValue)
- {
- GlobalObjectInit();
- objValue.pvValue = initialValue;
- iObjectSize = sizeof(initialValue) / SizeBasis;
- }
-
- //-----------------------------------------
- // "void *" object with size specified:
- GenericObject(void *initialValue, int initialSize)
- {
- GlobalObjectInit();
- objValue.pvValue = initialValue;
- iObjectSize = initialSize;
- }
-
- //-------------------------------
- // Get the object's class name
- char *GetClassName()
- {
- return szClassName;
- }
-
- //-------------------------------
- // If iMaxReferenceCount is non-zero,
- // Increment reference count, return
- // new count, or -1 if maximum count
- // is exceeded; otherwise, just
- // increment the reference count (no
- // maximum limit).
- int ReferenceObject()
- {
- if (iReferenceCount)
- return (iReferenceCount < (iMaxReferenceCount-1)) ?
- ++iReferenceCount
- :
- -1;
- else
- return ++iReferenceCount;
- }
-
- //-------------------------------
- // Decrement reference count,
- // return new count or zero if
- // no outstanding references
- int DeReferenceObject()
- {
- return iReferenceCount ?
- --iReferenceCount
- :
- 0;
- }
-
- //-------------------------------
- // Return the object's size in
- // whatever unit is being used
- int &ObjectSize()
- {
- return iObjectSize;
- }
-
- //-------------------------------
- // Get / set reference count
- int &ReferenceCount()
- {
- return iReferenceCount;
- }
-
- //-------------------------------
- // Get / set max reference count
- int &MaxReferenceCount()
- {
- return iMaxReferenceCount;
- }
-
- //-------------------------------
- // Value method - get or set
- // the object's value
- GenericDataType &ObjectValue()
- {
- return objValue;
- }
-
- //-------------------------------
- // Conversion functions:
- // Convert object value to
- // an intrinsic data type.
- //
- // "char" object:
- operator char()
- {
- return objValue.cValue;
- }
-
- //-------------------------------
- // "unsigned char" object:
- operator unsigned char()
- {
- return objValue.ucValue;
- }
-
- //-------------------------------
- // "int" object:
- operator int()
- {
- return objValue.uiValue;
- }
-
- //-------------------------------
- // "unsigned int" object:
- operator unsigned int()
- {
- return objValue.uiValue;
- }
-
- //-------------------------------
- // "long" object:
- operator long()
- {
- return objValue.lValue;
- }
-
- //-------------------------------
- // "unsigned long" object:
- operator unsigned long()
- {
- return objValue.ulValue;
- }
-
- //-------------------------------
- // "char *" object:
- operator char *()
- {
- return objValue.szValue;
- }
-
- //-------------------------------
- // "void *" object:
- operator void *()
- {
- return objValue.pvValue;
- }
-
- //------------------------------------------------------
-
- };
-
- //-----------------------------------------------------
- // Now, define a specific class; integers in this case.
-
- class Integer : public GenericObject
- {
-
-
- public:
-
- //-------------------------------
- // Need a constructor for each
- // integral type even though
- // the parent class already
- // has a set including them
- //
- // Constructors:
- //
- // No type, value, etc specified
- Integer() : GenericObject() // Initialize
- { // parent class
- szClassName = "Integer_Class"; // constructor
- }
-
- //-------------------------------
- // "char" object:
- Integer(char initialValue) : GenericObject(initialValue)
- {
- szClassName = "Integer_Class";
- }
-
- //-------------------------------
- // "unsigned char" object:
- Integer(unsigned char initialValue) : GenericObject(initialValue)
- {
- szClassName = "Integer_Class";
- }
-
- //-------------------------------
- // "int" object:
- Integer(int initialValue) : GenericObject(initialValue)
- {
- szClassName = "Integer_Class";
- }
-
- //-------------------------------
- // "unsigned int" object:
- Integer(unsigned int initialValue) : GenericObject(initialValue)
- {
- szClassName = "Integer_Class";
- }
-
- //-------------------------------
- // "long" object:
- Integer(long initialValue) : GenericObject(initialValue)
- {
- szClassName = "Integer_Class";
- }
-
- //-------------------------------
- // "unsigned long" object
- Integer(unsigned long initialValue) : GenericObject(initialValue)
- {
- szClassName = "Integer_Class";
- }
-
- //-------------------------------
- // Conversion functions are inher-
- // ited from the parent class
- //
- //-------------------------------
- // Overload the standard math
- // operators - the compiler may
- // not be able to tell which
- // conversion function to apply;
- // that process has to be done
- // explicitly here.
- //
- // This is a round-about process;
- // the argument to the operator is
- // always an intrinsic data type
- // BECAUSE of the conversion
- // functions; the operators
- // must be overloaded BECAUSE of
- // the conversion functions.
- //-------------------------------
- // NOTE: There's no need to overload
- // the assignment operator. The
- // compiler will pick an applicable
- // constructor, called a "copy con-
- // structor", create an interim
- // class, and perform the assigment
- // automatically. You *can* provide
- // your own copy constructor, but
- // it's rare to need to do so.
- //-------------------------------
-
- //-------------------------------
- // Addition
- operator+(int x)
- {
- return objValue.iValue + x;
- }
-
- //-------------------------------
- // Subtraction
- operator-(int x)
- {
- return objValue.iValue - x;
- }
-
- //-------------------------------
- // Multiplication
- operator*(int x)
- {
- return objValue.iValue * x;
- }
-
- //-------------------------------
- // Division
- operator/(int x)
- {
- return objValue.iValue / x;
- }
-
- //-------------------------------
- // Modulus
- operator%(int x)
- {
- return objValue.iValue % x;
- }
-
- };
-
- //============================================================================//
- #ifdef __BUILD_SAMPLE__
-
- #include <stdio.h>
-
- int main(void);
-
- int main()
- {
- // Declare instances
- Integer a,b;
-
- // Use the constructors
- a = 50;
- b = 25;
-
- // See what type they are
- printf("a and b are of class %s and %s.\n",
- a.GetClassName(),
- b.GetClassName());
-
- // Use the overloaded operators and conversion functions
- a = a + b;
-
- // Note that a *must* be explicitly typecast in calls
- // to functions with variable argument lists. Conversion
- // is supplied only for the explicit parameters; in the
- // case of printf(), the prototype is something
- // (depending on your compiler; there might some minor
- // differences, but nothing substantial) like this:
- //
- // int printf(const char *,...);
- //
- // So, the compiler has no way to tell what conversion
- // function to use. What it ends up doing is
- printf("The value of a is %d.\n",(int)a);
-
- // Try another operator and more conversions; b is 25, so b*5 should be 125.
- b = b * 5;
- printf("The value of b is %d.\n",(int)b);
-
- // All done
- return 0;
-
- }
-
- #endif //(build sample)
-
- //============================================================================//