MFC Grid manual

How to serialize C++ object to an archive?

//For serialization an object should implement pairs of Get- and Set- methods.


//MyClass.h file

//This is a declaration of class, an instance of which can be serialized and deserialized to/from the binary form.
//The class has pairs of Set- and Get- methods that can be called by their identifiers. Also it has a default constructor.
class CMyClass : public Dapfor::Common::CDataObject
{
public:
    //It is better to use enumerations instead of long numeric values...
    //The grid can use the same identifiers to display values returned by 
    //functions of the class.
    enum
    {
        FidPrice,
        FidQuantity,
        FidTime,
        FidCity,
    };

    //Some cities...
    enum City
    {
        London = 100,
        Paris,
        Totonto,
        NewYork,
    };

public:
    CMyClass();
    ~CMyClass();


    //Get- methods
    double  GetPrice() const;
    __int64 GetQuantity() const;
    long    GetTime() const;
    long    GetCity() const;

    //Set- methods
    void  SetPrice(double newPrice);
    void  SetQuantity(__int64 newQuantity);
    void  SetTime(long newTime);
    void  SetCity(long newCity);


private:
    //Private fields
    double  m_Price;
    __int64 m_Quantity;
    long    m_Time;
    City    m_City;

    //Fieldmap declaration.
    DF_DECLARE_FIELD_MAP();

    //Serializable type declaration.
    DF_DECLARE_SERIALIZABLE_TYPE();
};


//MyClass.cpp file



// Enum format strings
Dapfor::Common::CLongEnumFormat::Item cities[] =
{
    {CMyClass::London,  "London"},
    {CMyClass::Paris,   "Paris"},
    {CMyClass::Totonto, "Totonto"},
    {CMyClass::NewYork, "NewYork"},
};


// Declaration of a field map.
// To put an object of CMyClass class into the grid, it is necessary to declare a table enabling calls of specified functions by identifiers. 
// Each data field should have a pair of Set and Get- functions.

DF_IMPLEMENT_SERIALIZABLE_TYPE(CMyClass)
DF_BEGIN_FIELD_MAP(CMyClass)
    DF_DOUBLE_ID(FidPrice,    "Price",    &CMyClass::GetPrice,    &CMyClass::SetPrice, 0)
    DF_INT64_ID (FidQuantity, "Quantity", &CMyClass::GetQuantity, &CMyClass::SetQuantity, 0)
    DF_LONG_ID  (FidTime,     "Time",     &CMyClass::GetTime,     &CMyClass::SetTime, new CCustomLongFormat())
    DF_LONG_ID  (FidCity,     "City",     &CMyClass::GetCity,     &CMyClass::SetCity, DF_ENUM_FORMAT(cities))
DF_END_FIELD_MAP()


CMyClass::CMyClass()
{
}

//Virtual destructor
CMyClass::~CMyClass()
{
    //Object ends the life cycle.
    NotifyDelete();
}


long CMyClass::GetCity() const
{
    return m_City;
}

double  CMyClass::GetPrice() const
{
    return m_Price;
}

__int64 CMyClass::GetQuantity() const
{
    return m_Quantity;
}

long CMyClass::GetTime() const
{
    return m_Time;
}


void  CMyClass::SetPrice(double newPrice)
{
    m_Price = newPrice;
    NotifyUpdate(FidPrice);
}

void  CMyClass::SetQuantity(__int64 newQuantity)
{
    m_Quantity = newQuantity;
    NotifyUpdate(FidQuantity);
}

void  CMyClass::SetTime(long newTime)
{
    m_Time = newTime;
    NotifyUpdate(FidTime);
}

void CMyClass::SetCity(long newCity)
{
    m_City = (City)newCity;
    NotifyUpdate(FidCity);
}





//How to serialize and deserialize a data object:

    //Create a serializer to store a data object
    CSerializer serializer1(CSerializer::Store);
    
    //Our data object
    CMyClass object1;
    object1.SetCity(CMyClass::London);
    object1.SetPrice(123.12);
    object1.SetQuantity(1234);

    //Serialize the name of the class
    serializer1 << object1.GetSerializationName();

    //Serialize the data object itself
    serializer1 << object1;

    //Copy data to the binary buffer
    long size = serializer1.GetSavingSize();
    unsigned char* buffer = new unsigned char[size];
    serializer1.SaveToBuffer(buffer);

    //Create a new serializer
    CSerializer serializer2(CSerializer::Restore);
    
    //Load data from the buffer
    serializer2.LoadFromBuffer(buffer, size);

    delete[] buffer;
    
    //Restore the class name
    std::string name;
    serializer2 >> name;
    
    //Try to create a new data object
    CDataObject* object2 = CTypeFactory::CreateObject(name);
    
    //Deserialise the object itself
    serializer2 >> *object2;

    //The object is created and deserialized.

    //To access to the data object without casting we can use field identifiers
    ASSERT(object2->GetLong(CMyClass::FidCity) == CMyClass::London);
    ASSERT(object2->GetDouble(CMyClass::FidPrice) == 123.12);
    ASSERT(object2->GetInt64(CMyClass::FidQuantity) == 1234);

    //There is another way to call methods: We can cast the type to the CMyClass. 
    //If RTTI is enabled, we can use dynamic_cast<> operator. 
    CMyClass* object3 = (CMyClass*)object2;
    ASSERT(object3->GetCity() == CMyClass::London);
    ASSERT(object3->GetPrice() == 123.12);
    ASSERT(object3->GetQuantity() == 1234);