Advanced Tools Module User’s Guide : PART II Advanced Tools Module Packages : Chapter 6 Using Object Serialization : Advanced Examples : Controlling the Scope of Object Reference Resolution
Controlling the Scope of Object Reference Resolution
Every time an object is inserted into an object stream, a context is established for the resolution of object references. For instance, the following code establishes a scope that matches the scope of the object cat. Object references contained within cat will be matched up as required.
 
// examples\serial\advanced\catanddog.h
 
class cat
{
RW_DECLARE_VIRTUAL_STREAM_FNS(cat)
public:
cat() { }
 
virtual ~cat() { }
 
cat(const RWCString color) : color_(color) { }
private:
RWCString color_;
};
 
cat* yellow_cat = new cat("yellow");
 
out << yellow_cat
Streaming Out Multiple Objects
But what happens when you stream out two objects, or three? What if we stream out cat followed by dog and then cat again?
 
dog* blue_dog = new dog("blue");
 
out << yellow_cat << blue_dog << yellow_cat;
 
Now you have three separate scopes reference resolution. If the same reference occurs in both contexts, as yellow_cat does here, it will be streamed out twice, once for each scope.
Streaming Multiple Objects into One Document
But what if you really only want one context? What if you want the second instance of yellow_cat in the stream to simply refer to the first one, thus preserving the fact that they are really the same object. One way to do this is to make use of the same mechanism employed by the streams to create these contexts in the first place. You do this by using the guard classes RWWithObjectOutputContext (for output) and RWWithObjectInputContext (for input). By creating these guards, you effectively create your own master context for resolution of object references.
To get both instances of streaming yellow_cat in the same context, all you have to do is this:
 
// examples\serial\advanced\catanddog.cpp
 
{ // 1
RWWithObjectOutputContext context(out); // 2
out << yellow_cat << blue_dog << yellow_cat; // 3
}
//1 Create a C++ context for our guard to work in.
//2 Create a streaming context, using the guard class. What this guard class does is to call the stream function openContext() on construction and closeContext() on destruction.
//3 Stream out as before.
You can achieve the same result by calling those functions directly:
 
out.openContext();
out << yellow_cat << blue_dog << yellow_cat;
out.closeContext();
But using the guard is a safer.
So now you have a single context containing all pets. The second time you stream out yellow_cat, the stream will contain a reference to the first yellow_cat rather than a whole new copy.
The code for input needs to match the code for output:
 
{
dog* blue_dog2;
cat* yellow_cat2;
cat* yellow_cat3;
RWWithObjectInputContext(in);
in << yellow_cat2 << blue_dog2 << yellow_cat3;
}
 
Now you have your pet collection. Both pointers yellow_cat2 and yellow_cat3 point to the same cat, as they should.