Virtual Functions saveGuts(RWFile&) and saveGuts(RWvostream&)
The
saveGuts(RWFile&) and
saveGuts(RWvostream&) virtual functions are responsible for polymorphically saving the internal state of an
RWCollectable object on either a binary file, using class
RWFile, or on a virtual output stream, using class
RWvostream. For a description of the persistence mechanism, see
Chapter 8. This allows the object to be restored at some later time, or in a different location. Here are some rules for defining a
saveGuts() function:
1. Save the state of your base class by calling its version of saveGuts().
2. For each type of member data, save its state. How to do this depends upon the type of the member data:
Primitives. For primitives, save the data directly. When saving to
RWFiles, use
RWFile::Write(); when saving to virtual streams, use the insertion operator
RWvostream::operator<<().
Rogue Wave classes. Most Rogue Wave classes offer an overloaded version of the insertion operator. For example,
RWCString offers:
RWvostream& operator<<(RWvostream&,
const RWCString& str);
Hence, many Rogue Wave classes can simply be shifted onto the stream.
Objects inheriting from RWCollectable. For most of these objects, use the global function:
RWvostream& operator<<(RWvostream&,
const RWCollectable& obj);
This function will call saveGuts() recursively for the object.
With these rules in mind, let's look at a possible definition of the saveGuts() functions for the Bus example:
void Bus::saveGuts(RWFile& f) const {
RWCollectable::saveGuts(f); // Save base class
f.Write(busNumber_); // Write primitive directly
f << driver_ << customers_; // Use Rogue Wave-
// provided versions
f << passengers_; // Will detect nil pointer
// automatically
}
void Bus::saveGuts(RWvostream& strm) const {
RWCollectable::saveGuts(strm); // Save base class
strm << busNumber_; // Write primitives directly
strm << driver_ << customers_; // Use Rogue Wave
// provided versions
strm << passengers_; // Will detect nil pointer
// automatically
}
Member data busNumber_ is an int, a C++ primitive. It is stored directly using either RWFile::Write(int), or RWvostream::operator<<(int).
Member data
driver_ is an
RWCString. It does
not inherit from
RWCollectable. It is stored using:
RWvostream& operator<<(RWvostream&, const RWCString&);
Member data
customers_ is an
RWSet. It
does inherit from
RWCollectable. It is stored using:
RWvostream& operator<<(RWvostream&, const RWCollectable&);
Finally, member data
passengers_ is a little tricky. This data is a pointer to an
RWSet, which inherits from
RWCollectable. However, there is the possibility that the pointer is nil. If it is nil, then passing it to:
RWvostream& operator<<(RWvostream&, const RWCollectable&);
would be disastrous, as we would have to dereference passengers_:
strm << *passengers_;
Instead, since our class has declared
passengers_ as an
RWSet*, we pass it to:
RWvostream& operator<<(RWvostream&, const RWCollectable*);
which automatically detects the nil pointer and stores a record of it.