External Serialization
In the following examples, all classes that have been defined in the previous examples are now being provided as part of a third party library that must be used without any modifications. This library does not have support for object serialization.
To provide serialization support for the classes in this library, you use the external serialization macros, which don’t require any changes to the existing class library.
Instead of inserting RW_DECLARE_VIRTUAL_STREAM_FNS() into the class declaration of real_property in the real_property.h header file, macro RW_DECLARE_EXTERNAL_STREAM_FNS() is placed in a new header file, such as real_property_ext.h. The macros RW_DECLARE_EXTERNAL_STREAMABLE_POINTER() and RW_DECLARE_EXTERNAL_STREAMABLE_AS_SELF() (and possibly RW_DECLARE_EXTERNAL_STREAMABLE_AS_BASE() if streaming through base class pointers) is also placed in this new file. This new header file needs to be included in any code that streams real_property objects.
In the next example, the real_property class is modified slightly to represent something you’d be more likely to see in the real world. It allows access to data members via public accessor functions.
 
// examples\serial\external\real_property.h
 
class real_property
{
public:
 
real_property () { }
 
virtual ~real_property() { } // 1
 
real_property (const RWCString& address,
const RWCString& size)
: address_(address), size_(size)
{}
 
bool operator== (const real_property& prop) const {
return_address_ == prop.address_;
}
 
RWCString setAddress(const RWCString& address) { // 2
RWCString tmp = address_;
address_ = address;
return tmp;
}
const RWCString& getAddress() const {
return address_;
}
RWCString setSize(const RWCString& size){
RWCString tmp = size_;
size_ = size;
return tmp;
}
const RWCString& getSize() const {
return size_;
}
 
private:
RWCString address_;
RWCString size_;
};
//1 At least one virtual function is needed, because the by-reference streaming facility relies on RTTI and that requires a v-table. A virtual streamContents() function cannot be used when using externally streaming; however, a virtual destructor can and would fulfill the requirement. Your classes will normally handle this as part of their interface.
//2 These accessor functions enable you to serialize the data members.
What follows is the new header from examples\serial\external\real_property_ext.h, which provides for the external serialization version of the class. It is the entire contents of the header, except for include guards and such.
 
#include <rw\serial\RWObjectStreamMacros.h> // 1
#include <real_property.h> // 2
 
// Allow object streaming
RW_DECLARE_EXTERNAL_STREAMABLE_AS_SELF(real_property)
RW_DECLARE_EXTERNAL_STREAMABLE_POINTER(real_property)
RW_DECLARE_EXTERNAL_STREAM_FNS(real_property) // 3
//1 Include the header to get the serialization macros.
//2 Include the header of the class to be serialized.
//3 Use the RW_DECLARE_EXTERNAL_STREAM_FNS macro and place it in this new file along with the RW_DECLARE_STREAMABLE_POINTER macro.
The macro calls that are normally put into an object’s source file, such as real_property.cpp, must be replaced by calls in a separate source file, such as real_property_ext.cpp. The macro RW_DEFINE_STREAMABLE_POINTER() is replaced by RW_DEFINE_EXTERNAL_STREAMABLE_POINTER(), RW_DEFINE_STREAMABLE_AS_SELF() is replaced by RW_DEFINE_EXTERNAL_STREAMABLE_AS_SELF(), and RW_BEGIN_STREAM_CONTENTS() is replaced by RW_BEGIN_EXTERNAL_STREAM_CONTENTS().
The macro calls used inside the streamContents() function may also be different. If the class in question inherits from another streamable class, then RW_STREAM_EXTERNAL_PARENT() is used instead of RW_STREAM_PARENT().
When used with external serialization, the RW_STREAM_ATTR_MEMBER() macro acts on public data members only. The RW_STREAM_ATTR_GET_SET() macro provides serialization of attributes for libraries with public “get” and “set” accessor functions. The following code shows a source module with external serialization macros. The sample represents the entire contents of the real_property_ext.cpp file.
 
// examples\serial\external\real_property_ext.cpp
 
#include "real_property_ext.h”
 
RW_BEGIN_EXTERNAL_STREAM_CONTENTS(real_property) // 1
RW_STREAM_ATTR_GET_SET(address,RWCString,getAddress,
setAddress) // 2
RW_STREAM_ATTR_GET_SET(size,RWCString,getSize,setSize)
RW_END_EXTERNAL_STREAM_CONTENTS
 
RW_DEFINE_EXTERNAL_STREAMABLE_AS_SELF(real_property)
RW_DEFINE_EXTERNAL_STREAMABLE_POINTER(real_property) // 3
//1 Note the use of the external version of this macro.
//2 The GET/SET macros provide access to data members via their get and set functions. The first parameter to the macro is the name of the data member, the second parameter is the type of the member, the third is the name of the get function (used by output streams to obtain a value), and the last parameter is the name of the set function (used by input streams to set a value).
//3 Again, note the use of the external version of the macros.
NOTE: You can put calls for related classes together in the same header or source file in your code. Classes within a hierarchy must either use external serialization or use the intrusive style. Mixed hierarchies are not supported.
To support the derived class residential, you can add to the two real_property_ext files as follows.
 
// examples\serial\external\real_property_ext2.h
 
#include <rw\serial\RWObjectStreamMacros.h>
#include <real_property.h>
 
// Allow object streaming
RW_DECLARE_STREAMABLE_AS_SELF(real_property)
RW_DECLARE_STREAMABLE_POINTER(real_property)
RW_DECLARE_EXTERNAL_STREAM_FNS(real_property)
 
RW_DECLARE_STREAMABLE_AS_SELF(residential)
RW_DECLARE_STREAMABLE_POINTER(residential)
RW_DECLARE_EXTERNAL_STREAM_FNS(residential) // 1
 
//1 Macro invocations for the residential class.
The next code sample is from: examples\serial\external\real_property_ext2.cpp.
 
#include <real_property_ext2.h>
 
RW_BEGIN_EXTERNAL_STREAM_CONTENTS(real_property)
{
RW_STREAM_ATTR_GET_SET(address,RWCString,getAddress,setAddress)
RW_STREAM_ATTR_GET_SET(size,RWCString,getSize,setSize)
}
RW_END_EXTERNAL_STREAM_CONTENTS
 
RW_DEFINE_EXTERNAL_STREAMABLE_AS_SELF(real_property)
RW_DEFINE_EXTERNAL_STREAMABLE_POINTER(real_property)
 
RW_BEGIN_EXTERNAL_STREAM_CONTENTS(residential)
{
RW_STREAM_EXTERNAL_PARENT(real_property) // 1
RW_STREAM_ATTR_GET_SET(footage, long, getFootage, setFootage)
}
RW_END_EXTERNAL_STREAM_CONTENTS
 
RW_DEFINE_EXTERNAL_STREAMABLE_AS_SELF(residential)
RW_DEFINE_EXTERNAL_STREAMABLE_AS_BASE(residential,real_property)
RW_DEFINE_EXTERNAL_STREAMABLE_POINTER(residential)
 
//1 Note the use of the external version of this macro.