home *** CD-ROM | disk | FTP | other *** search
- //========================================================================
- // The following information has been provided by the Technical
- // Support staff at Borland International. It is provided as a
- // courtesy and not as part of a Borland product, and as such, is
- // provided without the assurance of technical support or any specific
- // guarantees.
- //========================================================================
-
- Topic: Streamable objects (persistance)
-
- Associated reading: Chapter 8, Ch. 13 p223-237, look at the source code in
- TVDemo that deals with saving and restoring the desktop.
- (TVDemo::saveDesktop() and TVDemo::storeDesktop() in tvdemo1.cpp and
- TVDemo::loadDesktop() and TVDemo::retrieveDesktop() in tvdemo3.cpp)
-
- Discussion: How can an object be created, saved and restored at a later
- time, but still have the properties the the previous object had?.
- Furthermore, can this be done with runtime identification of what the
- object actually was? Class TStreamable is a required base class for
- any persistant object and TView is derived from both TObject and
- TStreamable. Thus any view that is displayed on the screen can be
- streamed (with a little modification to the class.) If such an object
- contains instances other objects they must be streamable as well. For
- example, a TListBox contains a TCollection*. If this had been a
- TNSCollection* (non-streamable collection) then a TListBox could not be
- safely streamed. We will use the a modified set of streams classes
- function from C++ streams to read/write data to auxilary storage media.
- The following is a list of steps needed to make an object streamable:
-
- 1) The object must have TStreamable in its hierarchy. Anything derived
- from TView already fits this. If you are deriving a new object from
- TObject and you want to be able to stream such items, then use
- multiple inheritance to also derive it from TStreamable.
-
- 2) Override the virtual read/write for data related to class (if the
- class is derived from something, then you will call the parents
- read/write function first. e.g. TView::write(). ) These should be
- protected data members. Prototypes are:
-
- void write( opstream& )
- void *read( ipstream& ) // returns 'this'
-
- 3) Include a private constructor which accepts one parameter of type
- streamableInit. Have the constructor call the parent class
- constructor and pass it the parameter streamableInit. e.g.
-
- TClassName( streamableInit ) : TView( streamableInit ) { }
-
- 4) Have a public member function that builds a 'template' for the
- object. This will be used by the stream manager to create an
- instance of an object whose data it is currently reading.
-
- TStreamable *TClassName::build()
- { return new TClassName( streamableInit ); }
-
- 5) Have a public static const character pointer called name. This
- should be initialized to a unique character string, normally the
- class name, e.g.
-
- const char * const TClassName::name = "TClassName";
-
- 6) You need to register the object with the stream manager. This
- requires creation of an object of type TStreamableClass and passing
- the name, address of the build member function and a third parameter
- to it's constructor. The name of this instance is normally
- RClassName. e.g.
-
- TStreamableClass RClassName( TClassName::name,
- TClassName::build,
- __DELTA( TClassName ) );
-
- Also, when you are using a class that descends from Turbo Vision
- objects, you have to pull in their registration instances too. This
- done with the __link() macro. You will have to use it for the TV
- class that you have derived your object from. It takes a single
- argument that is the class name of the TV class involved, except the
- first letter is an 'R' instead of a 'T'. If you derived TMyWindow
- from TWindow, you would do this:
-
- __link( RWindow );
-
- 7) This is optional, but you can overload the >> and << operators for
- this object with the following lines:
-
- inline ipstream& operator >> (ipstream& is, TClassName & cl)
- { return is >> (TStreamable&) cl; }
- inline ipstream& operator >> (ipstream& is, TClassName *& cl)
- { return is >> (void *&) cl; }
- inline opstream& operator << (opstream& os, TClassName & cl)
- { return os << (TStreamable&) cl; }
- inline opstream& operator << (opstream& os, TClassName * cl)
- { return os << (TStreamable *) cl; }
-
- As an exercise, try making the desktop objects streamable and implement
- two menu items which will save and restore the desktop. Saving the
- contents simply requires using the forEach() member function to iterate
- through the items in the desktop, writing each out to the stream as we
- go. Restoring is a little different because you must first clear the
- current desktop before reading in the new items. (If you did not clear
- the current desktop, then where would those objects go when the old
- desktop was restored?) Once the desktop is cleared, you can read in
- the items and insert them.
-
- Add two new menu items - Save and Restore Desktop. Add stream support
- to the objects in the program that can go in the desktop. See the above
- discussion and the TV Demo source code for examples of streaming a
- class. (e.g. PUZZLE.CPP and PUZZLE.H.) The save/restore items are
- easy to implement - you don't have to cycle through the items inserted
- in the desktop, simply use the << or >> operators to send
- TProgram::deskTop out/in the stream.
-
- Classes used:
-
- i/ofpstream - These are the names of the stream objects you will be
- working with, rather than the normal C++ iostream library functions.
-
- TStreamable - Base class for all streamable objects. Any class that
- is streamed MUST be descended from this class. (Note: Anything
- derived from TView already meets this requirement.)
-
- TStreamableClass - An object of this type is created for the purposes of
- registering a new object with the streams. This gives the stream
- manager the tools to build an object that is being read.
-
- Macros:
-
- __link( RTVClassName ) - Used to register the Turbo Vision object
- RTVClassName.
-
- __DELTA( TClassName ) - This calculates the difference in address value
- between a TClassName* and the embedded TStreamable* within.
- TClassName has multiple base classes, TStreamable and TObject, so
- these addresses are not necessarily the same. The stream manager
- needs this delta value to be able to properly cast a TStreamable*
- back to the object it is supposed to be.
-