home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
alloop.zip
/
ALLOOP.CPP
next >
Wrap
Text File
|
1994-05-01
|
30KB
|
721 lines
//----------------------------------------------------------------------------//
// (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)
//============================================================================//