PRODUCT : Borland C++ NUMBER : 1381 VERSION : 3.x OS : ALL DATE : October 25, 1993 PAGE : 1/7 TITLE : Deriving from Object with the object class libraries 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; PRODUCT : Borland C++ NUMBER : 1381 VERSION : 3.x OS : ALL DATE : October 25, 1993 PAGE : 2/7 TITLE : Deriving from Object with the object class libraries 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. As 'const' was used in the abstract base declaration of these functions it is important to maintain the 'const' when re- defining. 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 PRODUCT : Borland C++ NUMBER : 1381 VERSION : 3.x OS : ALL DATE : October 25, 1993 PAGE : 3/7 TITLE : Deriving from Object with the object class libraries 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 MYOBJECT.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 #include #include /* this enum is an easy way to return a unique class type identification for user-defined Objects */ PRODUCT : Borland C++ NUMBER : 1381 VERSION : 3.x OS : ALL DATE : October 25, 1993 PAGE : 4/7 TITLE : Deriving from Object with the object class libraries 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 #include PRODUCT : Borland C++ NUMBER : 1381 VERSION : 3.x OS : ALL DATE : October 25, 1993 PAGE : 5/7 TITLE : Deriving from Object with the object class libraries #include #include #include #include #include #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; } PRODUCT : Borland C++ NUMBER : 1381 VERSION : 3.x OS : ALL DATE : October 25, 1993 PAGE : 6/7 TITLE : Deriving from Object with the object class libraries 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<