Listing 2: UIOObj.h — TIOObjectBase class and TIOObject class templates

//---------------------------------------------------------------
#ifndef UIOObjH
#define UIOObjH
#pragma hdrstop
#include <stlcomp.h>
#include <typeinfo.h>
#include <map.h>
#include <cstring.h>
#include <strstrea.h>
#include <fstream.h>

// problem with Borland C++ and SGI templates?
// compiler error if not less<string> specialized!
// C++ BUILDER HAS NO SUCH PROBLEM

struct less<string> {
   bool operator()(const string& x, const string& y) const
      { return (x < y); }
};

//---------------------------------------------------------------
class TIOObjectBase  {
      enum {MAX_NAME_SIZE = 70};
   public:
      // exception types
      struct exception {
         string mess;
         exception(const char * _mess): mess(_mess) {}
         virtual ~exception() {}
      };
      struct EUnknownClass : public exception {
          EUnknownClass(const char * _className):
             exception(_className) {}
      };
      struct EEof : public exception {
          EEof(const char * which=NULL):
             exception(which) {}
      };
   protected:
      void write(ostrstream & mem);
      static string readClassName(strstream & str)
            throw (exception*) ;
      static string readClassName(fstream& fstr)
              throw (exception*, EEof*) ;
      virtual void* dataStart(void) const = 0;
      virtual size_t dataSize(void) const = 0;
      typedef  TIOObjectBase* (*pfCreate)(fstream&);

      // for the input "virtual constructor" Create
      typedef map<string, pfCreate, less<string> >  CreateMap;
      static CreateMap* pCreateMap;
    public:
      virtual ~TIOObjectBase() {}

      // use to UN-Register() ALL and CLEANUP AFTER USE
      static void reset();
      virtual string name(void) const = 0;
      void write(fstream& fstr);
      static TIOObjectBase* Create( fstream& )
                     throw (exception*, EUnknownClass*) ;
};

//---------------------------------------------------------------
template <class T>
class TIOObject : public virtual TIOObjectBase {
   private:
      T Data;
      static TIOObjectBase* create(fstream& )
                throw (exception*);
   protected:
      void* dataStart(void) const {return (void*)&Data;}
      size_t dataSize(void) const {return sizeof Data;}
      static string Name(void){return typeid(TIOObject).name();}
      string name(void) const {return Name();}
    public:

      TIOObject(const T& _data = T()):  Data(_data) {}
      // RECOGNIZE the type AND access the data :
      //    IF pIOObjectBase IS a TIOObject<T>* returns a T*
      //    ELSE returns 0

      static T* PtrData(TIOObjectBase* pIOObjectBase);
      static void Register(void);
};

//---------------- TEMPLATE FUNCTION DEFINITIONS ----------------
//

//---------------------------------------------------------------
template <class T>
TIOObjectBase* TIOObject<T>::create(fstream& fstr)
                  throw (exception*)
{
   TIOObject* ptr = new TIOObject;
   fstr.read((char*)ptr->dataStart(), ptr->dataSize());
   if (fstr.eof())
      throw new exception("unexpected end of file");
   return ptr;
}

//---------------------------------------------------------------
// NB: although TIOObject<T> only has one data member, T Data
// a TIOObject* DOES NOT HAVE SAME ADDRESS AS ITS Data MEMBER!!!
// &(pIOObject->Data) < pIOObject->Data !!!

template <class T>
T* TIOObject<T>::PtrData(TIOObjectBase* pIOObjectBase)
{
   TIOObject * pIOObject;
   if ((pIOObject = dynamic_cast<TIOObject<T>* >(pIOObjectBase))
          != NULL )
      return &(pIOObject->Data);
   else
      return NULL;
}

//---------------------------------------------------------------
template <class T>
void TIOObject<T>::Register(void) {
   if (!TIOObjectBase::pCreateMap)
      pCreateMap = new CreateMap();
   (*pCreateMap)[Name()] = create;
}


#endif

//End of File