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_;
};
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
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
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
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)