home *** CD-ROM | disk | FTP | other *** search
- //========================================================================
- // The following example routines have been provided by the Technical
- // Support staff at Borland International. They are provided as a
- // courtesy and not as part of a Borland product, and as such, are
- // 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 member
- functions saveDesktop() & storeDesktop() in tvdemo1.cpp and loadDesktop() &
- retrieveDesktop() in tvdemo3.cpp)
-
- Discussion: How can an object be created, saved and restored at a later
- time, but still have the properties that the previous object had?
- Furthermore, can this be done with runtime identification of what the
- object actually was? This property of objects is called persistance.
- 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 such an object contains instances or pointers to 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 a
- modified set of stream classes derived from the C++ streams to read/write
- data to auxiliary 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:
-
- virtual void write( opstream& )
- virtual void *read( ipstream& ) // returns 'this'
-
- 3) Include a private constructor which accepts one parameter of type
- StreamableInit (this is a typedef for '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 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. The prototype is TStreamable *build() and
- here is an example:
-
- 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) Have a public function called streamableName() that returns the above
- string, name. It's implemented like this:
-
- virtual const char *streamableName() const
- { return name; }
-
- 7) 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 );
-
- 8) 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; }
-
- In this example, we are going to make our 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 w as
- restored?) Once the desktop is cleared, you can read in the items and
- insert them.
-
- File name: streams.cpp
-
- Do: Add two new menu items - Save and Restore Desktop to the program
- provided. Add stream support to the objects in the program that can go in
- the desktop. Because adding stream support is nearly an identical task for
- any object, this project has a special program that only has a few different
- views available. 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 rough 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.
-