How to derive a class from Object for use with the Object-based 
Container class library. 

The Object-based Container class Library:

The Object-based Container class is designed to contain Objects. For
example, the Array class can readily contain and manipulate objects of
the String class. But, an attempt to add a user-defined structure or class
to an Array will generate errors: "type mismatch" and "cannot initialize 
'Object&' with 'MyType'". To take advantage of the Container library with
a user-defined type, it is necessary to provide a class which not only 
contains ones own members and methods but also is a derivative of class 
Object.

Making the Abstract Concrete: 

"Object" is an abstract class. This means that the class designer has 
declared one or more functions as pure virtual, with the intent that the 
derived class will further describe the behavior of the class by providing
the pure virtual functions. Providing definitions of these functions is not 
by choice and is enforced by the rules of C++. An attempt to declare an 
instance of an Object will result in an error: "Cannot create instance of 
an abstract class". The key, then, is to provide, in our class, the pure 
virtual functions of the abstract base class so that the class can be 
instantiated. After the Object-derived class is instantiable it will then 
have, not only our own unique members and methods, but the behavior of an 
Object. As we are derived from Object, the C++ concept of polymorphism will 
allow our class to be used in the same manner an Object can be used. We will
be able to add our own object to an Array or any other Container that 
manipulates Objects.


  There are five pure virtual functions we need to define:

    virtual classType isA() const = 0;
    virtual char _FAR *nameOf() const = 0;
    virtual hashValueType hashValue() const = 0;
    virtual int isEqual( const Object _FAR & ) const = 0;
    virtual void printOn( ostream _FAR & ) const = 0;

The example class, MyObject, defines these five functions, and then 
tests the new Object by adding it to an Array.

Notes:
What these functions do:
  isA:       Class type identification
  nameOf:    Class Name identification
  hashValue: returns a hash value for mapping arbitrary value into a range
  isEqual:   a means of determining equality of two objects
  printOn:   a member function for outputting values of the Object, used
             by the overloaded ostream operator<< 

const functions.
  The 'const' is important when defining these functions. If it is 
  missing the declaration is seen as a unique function and the only
  error generated will be "Cannot create instance of abstract class 
  'MyObject'", as we have not successfully provided a definition of
  the original pure virtual function.


Object-based Container library.
  The reason "Object-based Container class" is stressed in this document 
  is to differentiate from the template-based Container library which does
  not require that user-defined types be derived from Object. If you use 
  the template class library instead of the object class library, you 
  don't need to derive from Object but you may need to provide certain 
  operators ( such as  ==  != < ) if getting "illegal structure operation"
  on the user-defined type.

Proper copy semantics.
  The MyObject example class also defines two additional functions:
      MyObject( const MyObject& );  // copy constructor
      MyObject& operator = ( const MyObject& ); // assignment operator
  These functions are not necessary to make the class instantiable but
  demonstrate a, sometimes essential, C++ practice known as "providing 
  proper copy semantics". Any C++ compiler will provide default versions 
  of these two functions, but if the class allocates memory, it is crucial
  to manage that memory in means appropriate to the particular class. 
  These functions are defined when a class wants to ensure safe memory
  management.
  
Compiling the example.
  There are two files MYOBJECT.CPP and MYOBECT.H. Load MYOBJECT.CPP into 
  the IDE, make sure Options | Linker | Libraries has the static Container 
  class library selected and that Options | Directories has paths set to 
  Include and Library Directories of both the Compiler and Classlib.

  From the command line, with a TURBOC.CFG like the following:

   -IC:\BORLANDC\INCLUDE;C:\BORLANDC\CLASSLIB\INCLUDE	
   -LC:\BORLANDC\LIB;C:\BORLANDC\CLASSLIB\LIB

    use the following for small model...
      bcc  myobject tclasss.lib

    OR use the following for large model...
      bcc -ml myobject tclassl.lib

/*------------------------------------------------------------------------*/
/*                                                                        */
/*  MYOBJECT.H                                                            */
/*  declares the user-defined type, MyObject a derivative of Object       */
/*------------------------------------------------------------------------*/

#include <string.h>
#include <clstypes.h>
#include <object.h>

/*
   this enum is an easy way to return a unique class
   type identification for user-defined Objects
*/
enum{  myobjectClass = __firstUserClass, myobjectClass2 };

class MyObject: public Object
{

public:

    MyObject( const char *nameinit, long telinit );
    MyObject( const MyObject& );
    virtual ~MyObject()
	   {
	   delete name;
	   }
    MyObject& operator = ( const MyObject& );
    virtual int isEqual( const Object& testMyObject ) const;
    virtual classType isA() const
	   {
	   return myobjectClass;
	   }

    virtual char *nameOf() const
	   {
	   return "MyObject";
	   }

    virtual hashValueType hashValue() const;
    virtual void printOn( ostream& ) const;

    sizeType len; // length of the name
    char  *name;  
    long tel;	 // telephone number
};
/*------------------------------------------------------------------------*/
/*                                                                        */
/*  MYOBJECT.CPP                                                          */
/*  Demonstrates a minimal class derivation from Object and               */
/*  then tests the new class by using it as an Object ( adds              */
/*  the MyObject class to an Array ).                                     */
/*                                                                        */
/*------------------------------------------------------------------------*/

#include <stdlib.h>
#include <string.h>
#include <clstypes.h>
#include <checks.h>
#include <iostream.h>
#include <iomanip.h>
#include <array.h>
#include "myobject.h"

MyObject::MyObject( const char *nameinit, long telinit=411 )
{
    if ( nameinit == 0 )
	   nameinit = "";

    len = strlen( nameinit ) + 1;
    name = new char[ len ];
    CHECK( name != 0 );
    strcpy( name, nameinit );
    tel = telinit;
}

MyObject::MyObject( const MyObject& other )
{
    len = other.len;
    name = new char[ len ];
    CHECK( name != 0 );
    strcpy( name, other.name );
    tel = other.tel;
}

MyObject::isEqual( const Object& testMyObject ) const
{
    return tel == ((MyObject&)testMyObject).tel ;
}


hashValueType MyObject::hashValue() const
{
    hashValueType  value = hashValueType(0);
    // the following conversion may lose significant digits
    // but we are just hoping to return a somewhat unique number
    value = (int)tel;
    return value;
}

void MyObject::printOn( ostream& outputStream ) const
{
    // the phone number is stored as a long but printed as a string
    char buff[25];
    char prefix[25];
    char num[25];
    ltoa( tel, buff, 10 );
    strcpy(prefix, buff );
    strcpy(num, buff+3 );
    prefix[3]=0;
    outputStream <<"Name: "<< name<<setw(20-len)<<"  Number: " << prefix;
    if( strlen(num) )
    outputStream << "-" << num;
}

MyObject& MyObject::operator=( const MyObject& other )
{
    if ( *this != other )
	   {
	   if ( len != other.len )
		  {
		  delete name;
		  len = other.len;
		  name = new char[ len ];
		  CHECK( name != 0 );

		  }
	   strcpy( name, other.name );
	   tel = other.tel;
	   }
    return *this;
}
main()
{
 // test whether the Object can be instantiated
  MyObject *obj1 = new MyObject("Larry", 8675309L );
  MyObject *obj2 = new MyObject("Moe"); // use default number
  MyObject *obj3 = new MyObject("Curly", 5551212L );

 // test using our Object by adding to an Array
  Array myArray(10);

  myArray.add( *obj1 );
  myArray.add( *obj2 );
  myArray.add( *obj3 );

 // display the Array of 'MyObject's
  cout << myArray << endl;

  return 0;
 }


